package eks

import (
	"fmt"
	"testing"

	"github.com/go-logr/logr"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	"github.com/tidbcloud/infra-provider/regional-server/api/v1alpha1"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/config"
	loadbalancertask "github.com/tidbcloud/infra-provider/regional-server/pkg/controllers/loadbalancer/task"
)

func TestServiceApplyDesiredStateLogValuesRedactsCIDRs(t *testing.T) {
	lb := &v1alpha1.LoadBalancer{
		ObjectMeta: metav1.ObjectMeta{
			Name:            "private-lb",
			ResourceVersion: "rv-123",
		},
		Spec: v1alpha1.LoadBalancerSpec{
			IpWhiteList: []string{
				"192.168.1.0/24",
				"10.0.0.0/16",
			},
		},
	}
	svc := &corev1.Service{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "tidb-svc",
			Namespace: "tidb-admin",
		},
		Spec: corev1.ServiceSpec{
			LoadBalancerSourceRanges: []string{
				"192.168.1.0/24",
				"172.31.23.64/32",
				"10.0.0.0/16",
			},
		},
	}

	got := toLogMap(serviceApplyDesiredStateLogValues(lb, svc))

	if got["loadBalancerIPWhiteListCount"] != 2 {
		t.Fatalf("loadBalancerIPWhiteListCount = %v, want 2", got["loadBalancerIPWhiteListCount"])
	}
	if got["desiredLoadBalancerSourceRangeCount"] != 3 {
		t.Fatalf("desiredLoadBalancerSourceRangeCount = %v, want 3", got["desiredLoadBalancerSourceRangeCount"])
	}
	assertLogMapOmitsCIDR(t, got, "192.168.1.0/24", "172.31.23.64/32", "10.0.0.0/16")
}

func TestServiceApplyActualStateLogValuesRedactsCIDRs(t *testing.T) {
	actual := &corev1.Service{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "tidb-svc",
			Namespace: "tidb-admin",
		},
		Spec: corev1.ServiceSpec{
			LoadBalancerSourceRanges: []string{
				"192.168.1.0/24",
				"10.0.0.0/16",
			},
		},
	}

	got := toLogMap(serviceApplyActualStateLogValues("private-lb", actual))

	if got["actualLoadBalancerSourceRangeCount"] != 2 {
		t.Fatalf("actualLoadBalancerSourceRangeCount = %v, want 2", got["actualLoadBalancerSourceRangeCount"])
	}
	assertLogMapOmitsCIDR(t, got, "192.168.1.0/24", "10.0.0.0/16")
}

func toLogMap(kvs []any) map[string]any {
	out := make(map[string]any, len(kvs)/2)
	for i := 0; i+1 < len(kvs); i += 2 {
		key, ok := kvs[i].(string)
		if !ok {
			continue
		}
		out[key] = kvs[i+1]
	}
	return out
}

func assertLogMapOmitsCIDR(t *testing.T, got map[string]any, cidrs ...string) {
	t.Helper()
	for key, value := range got {
		for _, cidr := range cidrs {
			if value == cidr {
				t.Fatalf("log field %s unexpectedly contains raw CIDR %s", key, cidr)
			}
		}
	}
}

func TestComputeTargetGroupAttributes(t *testing.T) {
	t.Parallel()

	defaultValue := func(preserve bool) string {
		return fmt.Sprintf("preserve_client_ip.enabled=%t", preserve)
	}

	withProxy := func(preserve bool) string {
		return defaultValue(preserve) + "," +
			"proxy_protocol_v2.client_to_server.header_placement=on_first_ack," +
			"proxy_protocol_v2.enabled=true"
	}

	withGraceful := func(prefix string) string {
		return prefix + "," +
			"target_health_state.unhealthy.connection_termination.enabled=false," +
			fmt.Sprintf("target_health_state.unhealthy.draining_interval_seconds=%d", gracefulUnhealthyDrainingIntervalSeconds)
	}

	cases := []struct {
		name                 string
		oldSvc               *corev1.Service
		preserveClientIP     bool
		disableProxyProtocol bool
		gracefulUnhealthy    bool
		want                 string
	}{
		{
			name:                 "nil old service uses default when proxy protocol disabled",
			oldSvc:               nil,
			preserveClientIP:     true,
			disableProxyProtocol: true,
			want:                 defaultValue(true),
		},
		{
			name:                 "nil old service uses default when proxy protocol disabled and preserve false",
			oldSvc:               nil,
			preserveClientIP:     false,
			disableProxyProtocol: true,
			want:                 defaultValue(false),
		},
		{
			name:                 "nil old service appends proxy protocol when enabled",
			oldSvc:               nil,
			preserveClientIP:     true,
			disableProxyProtocol: false,
			want:                 withProxy(true),
		},
		{
			name:                 "nil old service appends proxy protocol when enabled with preserve false",
			oldSvc:               nil,
			preserveClientIP:     false,
			disableProxyProtocol: false,
			want:                 withProxy(false),
		},
		{
			name:                 "graceful unhealthy appends target unhealthy behavior",
			oldSvc:               nil,
			preserveClientIP:     true,
			disableProxyProtocol: false,
			gracefulUnhealthy:    true,
			want:                 withGraceful(withProxy(true)),
		},
		{
			name: "old service keeps existing attributes when graceful unhealthy is disabled",
			oldSvc: &corev1.Service{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{
				targetGroupAttributesKey: "custom=true",
			}}},
			preserveClientIP:     true,
			disableProxyProtocol: true,
			want:                 "custom=true",
		},
		{
			name: "old service keeps existing attributes even if preserve differs",
			oldSvc: &corev1.Service{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{
				targetGroupAttributesKey: "preserve_client_ip.enabled=false",
			}}},
			preserveClientIP:     true,
			disableProxyProtocol: false,
			want:                 "preserve_client_ip.enabled=false",
		},
		{
			name: "old service returns empty annotation value",
			oldSvc: &corev1.Service{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{
				targetGroupAttributesKey: "",
			}}},
			preserveClientIP:     true,
			disableProxyProtocol: false,
			want:                 "",
		},
		{
			name:                 "old service with nil annotations returns default without proxy protocol",
			oldSvc:               &corev1.Service{},
			preserveClientIP:     false,
			disableProxyProtocol: false,
			want:                 defaultValue(false),
		},
		{
			name: "old service with unrelated annotations returns default without proxy protocol",
			oldSvc: &corev1.Service{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{
				"other": "value",
			}}},
			preserveClientIP:     true,
			disableProxyProtocol: false,
			want:                 defaultValue(true),
		},
		{
			name: "old service appends graceful unhealthy attributes to existing attributes",
			oldSvc: &corev1.Service{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{
				targetGroupAttributesKey: "custom=true",
			}}},
			preserveClientIP:     true,
			disableProxyProtocol: true,
			gracefulUnhealthy:    true,
			want:                 withGraceful("custom=true"),
		},
		{
			name: "old service replaces existing graceful unhealthy attributes",
			oldSvc: &corev1.Service{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{
				targetGroupAttributesKey: "custom=true,target_health_state.unhealthy.draining_interval_seconds=10,target_health_state.unhealthy.connection_termination.enabled=true",
			}}},
			preserveClientIP:     true,
			disableProxyProtocol: true,
			gracefulUnhealthy:    true,
			want:                 withGraceful("custom=true"),
		},
		{
			name: "old service deduplicates graceful unhealthy attributes",
			oldSvc: &corev1.Service{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{
				targetGroupAttributesKey: "custom=true,target_health_state.unhealthy.draining_interval_seconds=10,target_health_state.unhealthy.draining_interval_seconds=20,target_health_state.unhealthy.connection_termination.enabled=true,target_health_state.unhealthy.connection_termination.enabled=true",
			}}},
			preserveClientIP:     true,
			disableProxyProtocol: true,
			gracefulUnhealthy:    true,
			want:                 withGraceful("custom=true"),
		},
		{
			name: "old service removes graceful unhealthy attributes when disabled",
			oldSvc: &corev1.Service{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{
				targetGroupAttributesKey: "custom=true,target_health_state.unhealthy.draining_interval_seconds=10,target_health_state.unhealthy.connection_termination.enabled=true",
			}}},
			preserveClientIP:     true,
			disableProxyProtocol: true,
			gracefulUnhealthy:    false,
			want:                 "custom=true",
		},
	}

	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			t.Parallel()

			got := computeTargetGroupAttributes(tc.oldSvc, tc.preserveClientIP, tc.disableProxyProtocol, tc.gracefulUnhealthy)
			if got != tc.want {
				t.Fatalf("computeTargetGroupAttributes() = %q, want %q", got, tc.want)
			}
		})
	}
}

func TestService_nodePrivateSubnetIDs(t *testing.T) {
	t.Run("return nil when node zones not configured", func(t *testing.T) {
		s := &Service{
			BaseTask: &loadbalancertask.BaseTask{Context: &loadbalancertask.Context{
				Logger: logr.Discard(),
				Config: config.RootConfig{ControllerConfig: config.ControllerConfig{RegionConfig: config.RegionConfig{Zones: []string{"z1", "z2"}}}},
				VPC: &v1alpha1.VPC{
					Spec:   v1alpha1.VPCSpec{Zones: []string{"z1", "z2"}},
					Status: v1alpha1.VPCStatus{PrivateSubnets: []v1alpha1.Subnet{{AvailabilityZone: "z1", SubnetID: "subnet-1"}}},
				},
			}},
		}

		got := s.nodePrivateSubnetIDs()
		if got != nil {
			t.Fatalf("nodePrivateSubnetIDs() = %v, want nil", got)
		}
	})

	t.Run("return node subnet ids in node zone order", func(t *testing.T) {
		s := &Service{
			BaseTask: &loadbalancertask.BaseTask{Context: &loadbalancertask.Context{
				Logger: logr.Discard(),
				Config: config.RootConfig{},
				VPC: &v1alpha1.VPC{Spec: v1alpha1.VPCSpec{NodeZones: []string{"z2", "z1"}}, Status: v1alpha1.VPCStatus{PrivateSubnets: []v1alpha1.Subnet{
					{AvailabilityZone: "z1", SubnetID: "subnet-1"},
					{AvailabilityZone: "z2", SubnetID: "subnet-2"},
				}}},
			}},
		}

		got := s.nodePrivateSubnetIDs()
		want := []string{"subnet-2", "subnet-1"}
		if len(got) != len(want) {
			t.Fatalf("nodePrivateSubnetIDs() len = %d, want %d", len(got), len(want))
		}
		for i := range want {
			if got[i] != want[i] {
				t.Fatalf("nodePrivateSubnetIDs()[%d] = %s, want %s", i, got[i], want[i])
			}
		}
	})

	t.Run("return nil when any node zone subnet missing", func(t *testing.T) {
		s := &Service{
			BaseTask: &loadbalancertask.BaseTask{Context: &loadbalancertask.Context{
				Logger: logr.Discard(),
				Config: config.RootConfig{},
				VPC: &v1alpha1.VPC{
					Spec:   v1alpha1.VPCSpec{NodeZones: []string{"z1", "z2"}},
					Status: v1alpha1.VPCStatus{PrivateSubnets: []v1alpha1.Subnet{{AvailabilityZone: "z1", SubnetID: "subnet-1"}}},
				},
			}},
		}

		got := s.nodePrivateSubnetIDs()
		if got != nil {
			t.Fatalf("nodePrivateSubnetIDs() = %v, want nil", got)
		}
	})
}

// TestService_overlayPrivateSvc_cassandraProxyGolden pins the cassandra-proxy
// NLB shape end-to-end: when the caller passes AWS-specific annotations
// through Spec.Annotations, every EKS Service annotation must match the
// manually maintained manifest exactly. Caller annotations must override the
// controller-computed defaults on key collisions.
func TestService_overlayPrivateSvc_cassandraProxyGolden(t *testing.T) {
	const (
		hcPath     = "service.beta.kubernetes.io/aws-load-balancer-healthcheck-path"
		hcPort     = "service.beta.kubernetes.io/aws-load-balancer-healthcheck-port"
		hcProtocol = "service.beta.kubernetes.io/aws-load-balancer-healthcheck-protocol"
	)
	s := &Service{
		BaseTask: &loadbalancertask.BaseTask{Context: &loadbalancertask.Context{
			Logger: logr.Discard(),
			Config: config.RootConfig{},
			LoadBalancer: &v1alpha1.LoadBalancer{
				ObjectMeta: metav1.ObjectMeta{Name: "cassandra-private-xyz"},
				Spec: v1alpha1.LoadBalancerSpec{
					Tags: map[string]string{},
					Ports: []v1alpha1.LoadBalancerPort{
						{Name: "cassandra", Port: 9042, TargetPort: 9042, Protocol: "TCP"},
						{Name: "cassandra-ssl", Port: 9142, TargetPort: 9142, Protocol: "TCP"},
					},
					Annotations: map[string]string{
						hcPath:                   "/ready",
						hcPort:                   "6060",
						hcProtocol:               "http",
						targetGroupAttributesKey: "preserve_client_ip.enabled=true,stickiness.enabled=false",
					},
				},
			},
		}},
	}

	svc := &corev1.Service{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{}}}
	s.overlayPrivateSvc(svc, nil)

	wantGolden := map[string]string{
		hcPath:                   "/ready",
		hcPort:                   "6060",
		hcProtocol:               "http",
		targetGroupAttributesKey: "preserve_client_ip.enabled=true,stickiness.enabled=false",
		"service.beta.kubernetes.io/aws-load-balancer-nlb-target-type": "ip",
		"service.beta.kubernetes.io/aws-load-balancer-scheme":          "internal",
		"service.beta.kubernetes.io/aws-load-balancer-type":            "external",
	}
	for k, want := range wantGolden {
		if got := svc.Annotations[k]; got != want {
			t.Fatalf("annotation %s = %q, want %q", k, got, want)
		}
	}
}

func TestService_overlayPrivateSvc_legacyNoAnnotationsPreserved(t *testing.T) {
	s := &Service{
		BaseTask: &loadbalancertask.BaseTask{Context: &loadbalancertask.Context{
			Logger: logr.Discard(),
			Config: config.RootConfig{ControllerConfig: config.ControllerConfig{DisableProxyProtocol: true}},
			LoadBalancer: &v1alpha1.LoadBalancer{
				ObjectMeta: metav1.ObjectMeta{Name: "tidb-group-private"},
				Spec: v1alpha1.LoadBalancerSpec{
					Tags: map[string]string{},
					Port: 4000,
				},
			},
		}},
	}

	svc := &corev1.Service{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{}}}
	s.overlayPrivateSvc(svc, nil)

	// Healthcheck annotations must remain absent when the caller does not
	// set them so existing tiproxy / TiDBGroup LBs keep their
	// TCP-on-data-port default.
	for _, k := range []string{
		"service.beta.kubernetes.io/aws-load-balancer-healthcheck-path",
		"service.beta.kubernetes.io/aws-load-balancer-healthcheck-port",
		"service.beta.kubernetes.io/aws-load-balancer-healthcheck-protocol",
	} {
		if _, ok := svc.Annotations[k]; ok {
			t.Fatalf("annotation %s must not be set when Spec.Annotations is empty", k)
		}
	}
	// Target group attributes must fall back to the historical computed default.
	if got, want := svc.Annotations[targetGroupAttributesKey], "preserve_client_ip.enabled=false"; got != want {
		t.Fatalf("target-group-attributes = %q, want %q", got, want)
	}
}

func TestService_overlayPublicSvc_UsesTypedPreserveClientIP(t *testing.T) {
	preserve := false
	s := &Service{
		BaseTask: &loadbalancertask.BaseTask{Context: &loadbalancertask.Context{
			Logger: logr.Discard(),
			Config: config.RootConfig{ControllerConfig: config.ControllerConfig{DisableProxyProtocol: true}},
			LoadBalancer: &v1alpha1.LoadBalancer{
				ObjectMeta: metav1.ObjectMeta{Name: "tidb-group-public"},
				Spec: v1alpha1.LoadBalancerSpec{
					Tags:             map[string]string{},
					Type:             v1alpha1.PublicLoadBalancerType,
					Port:             4000,
					PreserveClientIP: &preserve,
				},
			},
		}},
	}

	svc := &corev1.Service{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{}}}
	s.overlayPublicSvc(svc, nil)

	if got, want := svc.Annotations[targetGroupAttributesKey], "preserve_client_ip.enabled=false"; got != want {
		t.Fatalf("target-group-attributes = %q, want %q", got, want)
	}
}

func TestService_overlayPublicSvc_DefaultPreserveClientIP(t *testing.T) {
	s := &Service{
		BaseTask: &loadbalancertask.BaseTask{Context: &loadbalancertask.Context{
			Logger: logr.Discard(),
			Config: config.RootConfig{ControllerConfig: config.ControllerConfig{DisableProxyProtocol: true}},
			LoadBalancer: &v1alpha1.LoadBalancer{
				ObjectMeta: metav1.ObjectMeta{Name: "tidb-group-public"},
				Spec: v1alpha1.LoadBalancerSpec{
					Tags: map[string]string{},
					Type: v1alpha1.PublicLoadBalancerType,
					Port: 4000,
				},
			},
		}},
	}

	svc := &corev1.Service{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{}}}
	s.overlayPublicSvc(svc, nil)

	if got, want := svc.Annotations[targetGroupAttributesKey], "preserve_client_ip.enabled=true"; got != want {
		t.Fatalf("target-group-attributes = %q, want %q", got, want)
	}
}

func TestService_overlayPrivateSvc_setsSubnetsAnnotationForNodeZones(t *testing.T) {
	s := &Service{
		BaseTask: &loadbalancertask.BaseTask{Context: &loadbalancertask.Context{
			Logger: logr.Discard(),
			Config: config.RootConfig{},
			VPC: &v1alpha1.VPC{Spec: v1alpha1.VPCSpec{NodeZones: []string{"z1", "z2"}}, Status: v1alpha1.VPCStatus{PrivateSubnets: []v1alpha1.Subnet{
				{AvailabilityZone: "z1", SubnetID: "subnet-1"},
				{AvailabilityZone: "z2", SubnetID: "subnet-2"},
			}}},
			LoadBalancer: &v1alpha1.LoadBalancer{Spec: v1alpha1.LoadBalancerSpec{Tags: map[string]string{}}, ObjectMeta: metav1.ObjectMeta{Name: "lb"}},
		}},
	}

	svc := &corev1.Service{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{}}}
	s.overlayPrivateSvc(svc, nil)

	got := svc.Annotations[subnetsAnnotationKey]
	want := "subnet-1,subnet-2"
	if got != want {
		t.Fatalf("subnets annotation = %q, want %q", got, want)
	}
}

func TestService_PrivateLinkTrafficAnnotation(t *testing.T) {
	t.Run("private lb sets inbound sg rules annotation to off", func(t *testing.T) {
		s := &Service{
			BaseTask: &loadbalancertask.BaseTask{Context: &loadbalancertask.Context{
				Logger: logr.Discard(),
				Config: config.RootConfig{},
				LoadBalancer: &v1alpha1.LoadBalancer{
					ObjectMeta: metav1.ObjectMeta{Name: "private-lb"},
					Spec:       v1alpha1.LoadBalancerSpec{Tags: map[string]string{}},
				},
			}},
		}

		svc := &corev1.Service{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{}}}
		s.overlayPrivateSvc(svc, nil)

		if got, want := svc.Annotations["service.beta.kubernetes.io/aws-load-balancer-inbound-sg-rules-on-private-link-traffic"], "off"; got != want {
			t.Fatalf("private link traffic annotation = %q, want %q", got, want)
		}
	})

	t.Run("public lb does not add inbound sg rules annotation", func(t *testing.T) {
		s := &Service{
			BaseTask: &loadbalancertask.BaseTask{Context: &loadbalancertask.Context{
				Logger: logr.Discard(),
				Config: config.RootConfig{},
				LoadBalancer: &v1alpha1.LoadBalancer{
					ObjectMeta: metav1.ObjectMeta{Name: "public-lb"},
					Spec:       v1alpha1.LoadBalancerSpec{Tags: map[string]string{}},
				},
			}},
		}

		svc := &corev1.Service{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{}}}
		s.overlayPublicSvc(svc, nil)

		if _, ok := svc.Annotations["service.beta.kubernetes.io/aws-load-balancer-inbound-sg-rules-on-private-link-traffic"]; ok {
			t.Fatalf("private link traffic annotation must not be set for public load balancer")
		}
	})
}

func TestService_nodePublicSubnetIDs(t *testing.T) {
	t.Run("return nil when node zones not configured", func(t *testing.T) {
		s := &Service{
			BaseTask: &loadbalancertask.BaseTask{Context: &loadbalancertask.Context{
				Logger: logr.Discard(),
				Config: config.RootConfig{ControllerConfig: config.ControllerConfig{RegionConfig: config.RegionConfig{Zones: []string{"z1", "z2"}}}},
				VPC: &v1alpha1.VPC{
					Spec:   v1alpha1.VPCSpec{Zones: []string{"z1", "z2"}},
					Status: v1alpha1.VPCStatus{PublicSubnets: []v1alpha1.Subnet{{AvailabilityZone: "z1", SubnetID: "subnet-pub-1"}}},
				},
			}},
		}

		got := s.nodePublicSubnetIDs()
		if got != nil {
			t.Fatalf("nodePublicSubnetIDs() = %v, want nil", got)
		}
	})

	t.Run("return node public subnet ids in node zone order", func(t *testing.T) {
		s := &Service{
			BaseTask: &loadbalancertask.BaseTask{Context: &loadbalancertask.Context{
				Logger: logr.Discard(),
				Config: config.RootConfig{},
				VPC: &v1alpha1.VPC{Spec: v1alpha1.VPCSpec{NodeZones: []string{"z2", "z1"}}, Status: v1alpha1.VPCStatus{PublicSubnets: []v1alpha1.Subnet{
					{AvailabilityZone: "z1", SubnetID: "subnet-pub-1"},
					{AvailabilityZone: "z2", SubnetID: "subnet-pub-2"},
				}}},
			}},
		}

		got := s.nodePublicSubnetIDs()
		want := []string{"subnet-pub-2", "subnet-pub-1"}
		if len(got) != len(want) {
			t.Fatalf("nodePublicSubnetIDs() len = %d, want %d", len(got), len(want))
		}
		for i := range want {
			if got[i] != want[i] {
				t.Fatalf("nodePublicSubnetIDs()[%d] = %s, want %s", i, got[i], want[i])
			}
		}
	})

	t.Run("return nil when any node zone public subnet missing", func(t *testing.T) {
		s := &Service{
			BaseTask: &loadbalancertask.BaseTask{Context: &loadbalancertask.Context{
				Logger: logr.Discard(),
				Config: config.RootConfig{},
				VPC: &v1alpha1.VPC{
					Spec:   v1alpha1.VPCSpec{NodeZones: []string{"z1", "z2"}},
					Status: v1alpha1.VPCStatus{PublicSubnets: []v1alpha1.Subnet{{AvailabilityZone: "z1", SubnetID: "subnet-pub-1"}}},
				},
			}},
		}

		got := s.nodePublicSubnetIDs()
		if got != nil {
			t.Fatalf("nodePublicSubnetIDs() = %v, want nil", got)
		}
	})
}

func TestService_overlayPublicSvc_setsSubnetsAnnotationForNodeZones(t *testing.T) {
	s := &Service{
		BaseTask: &loadbalancertask.BaseTask{Context: &loadbalancertask.Context{
			Logger: logr.Discard(),
			Config: config.RootConfig{},
			VPC: &v1alpha1.VPC{Spec: v1alpha1.VPCSpec{NodeZones: []string{"z1", "z2"}}, Status: v1alpha1.VPCStatus{PublicSubnets: []v1alpha1.Subnet{
				{AvailabilityZone: "z1", SubnetID: "subnet-pub-1"},
				{AvailabilityZone: "z2", SubnetID: "subnet-pub-2"},
			}}},
			LoadBalancer: &v1alpha1.LoadBalancer{Spec: v1alpha1.LoadBalancerSpec{Tags: map[string]string{}}, ObjectMeta: metav1.ObjectMeta{Name: "lb"}},
		}},
	}

	svc := &corev1.Service{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{}}}
	s.overlayPublicSvc(svc, nil)

	got := svc.Annotations[subnetsAnnotationKey]
	want := "subnet-pub-1,subnet-pub-2"
	if got != want {
		t.Fatalf("subnets annotation = %q, want %q", got, want)
	}
}
