Copilot commented on code in PR #90:
URL:
https://github.com/apache/cloudstack-kubernetes-provider/pull/90#discussion_r2618499162
##########
cloudstack_loadbalancer_test.go:
##########
@@ -764,3 +765,2932 @@ func TestCheckLoadBalancerRule(t *testing.T) {
}
})
}
+
+func TestRuleToString(t *testing.T) {
+ tests := []struct {
+ name string
+ rule *cloudstack.FirewallRule
+ want string
+ }{
+ {
+ name: "TCP rule",
+ rule: &cloudstack.FirewallRule{
+ Protocol: "tcp",
+ Cidrlist: "10.0.0.0/8",
+ Ipaddress: "203.0.113.1",
+ Startport: 80,
+ Endport: 80,
+ },
+ want: "{[10.0.0.0/8] -> 203.0.113.1:[80-80] (tcp)}",
+ },
+ {
+ name: "UDP rule",
+ rule: &cloudstack.FirewallRule{
+ Protocol: "udp",
+ Cidrlist: "192.168.0.0/16",
+ Ipaddress: "203.0.113.2",
+ Startport: 53,
+ Endport: 53,
+ },
+ want: "{[192.168.0.0/16] -> 203.0.113.2:[53-53] (udp)}",
+ },
+ {
+ name: "TCP rule with port range",
+ rule: &cloudstack.FirewallRule{
+ Protocol: "tcp",
+ Cidrlist: "0.0.0.0/0",
+ Ipaddress: "203.0.113.3",
+ Startport: 8000,
+ Endport: 8999,
+ },
+ want: "{[0.0.0.0/0] -> 203.0.113.3:[8000-8999] (tcp)}",
+ },
+ {
+ name: "ICMP rule",
+ rule: &cloudstack.FirewallRule{
+ Protocol: "icmp",
+ Cidrlist: "10.0.0.0/8",
+ Ipaddress: "203.0.113.4",
+ Icmptype: 8,
+ Icmpcode: 0,
+ },
+ want: "{[10.0.0.0/8] -> 203.0.113.4 [8,0] (icmp)}",
+ },
+ {
+ name: "unknown protocol",
+ rule: &cloudstack.FirewallRule{
+ Protocol: "gre",
+ Cidrlist: "10.0.0.0/8",
+ Ipaddress: "203.0.113.6",
+ },
+ want: "{[10.0.0.0/8] -> 203.0.113.6 (gre)}",
+ },
+ {
+ name: "nil rule",
+ rule: nil,
+ want: "nil",
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got := ruleToString(tt.rule)
+ if got != tt.want {
+ t.Errorf("ruleToString() = %q, want %q", got,
tt.want)
+ }
+ })
+ }
+}
+
+func TestRulesToString(t *testing.T) {
+ tests := []struct {
+ name string
+ rules []*cloudstack.FirewallRule
+ want string
+ }{
+ {
+ name: "empty list",
+ rules: []*cloudstack.FirewallRule{},
+ want: "",
+ },
+ {
+ name: "single rule",
+ rules: []*cloudstack.FirewallRule{
+ {
+ Protocol: "tcp",
+ Cidrlist: "10.0.0.0/8",
+ Ipaddress: "203.0.113.1",
+ Startport: 80,
+ Endport: 80,
+ },
+ },
+ want: "{[10.0.0.0/8] -> 203.0.113.1:[80-80] (tcp)}",
+ },
+ {
+ name: "multiple rules",
+ rules: []*cloudstack.FirewallRule{
+ {
+ Protocol: "tcp",
+ Cidrlist: "10.0.0.0/8",
+ Ipaddress: "203.0.113.1",
+ Startport: 80,
+ Endport: 80,
+ },
+ {
+ Protocol: "udp",
+ Cidrlist: "192.168.0.0/16",
+ Ipaddress: "203.0.113.2",
+ Startport: 53,
+ Endport: 53,
+ },
+ {
+ Protocol: "icmp",
+ Cidrlist: "0.0.0.0/0",
+ Ipaddress: "203.0.113.3",
+ Icmptype: 8,
+ Icmpcode: 0,
+ },
+ },
+ want: "{[10.0.0.0/8] -> 203.0.113.1:[80-80] (tcp)},
{[192.168.0.0/16] -> 203.0.113.2:[53-53] (udp)}, {[0.0.0.0/0] -> 203.0.113.3
[8,0] (icmp)}",
+ },
+ {
+ name: "rules with nil rule",
+ rules: []*cloudstack.FirewallRule{
+ {
+ Protocol: "tcp",
+ Cidrlist: "10.0.0.0/8",
+ Ipaddress: "203.0.113.1",
+ Startport: 80,
+ Endport: 80,
+ },
+ nil,
+ {
+ Protocol: "udp",
+ Cidrlist: "192.168.0.0/16",
+ Ipaddress: "203.0.113.2",
+ Startport: 53,
+ Endport: 53,
+ },
+ },
+ want: "{[10.0.0.0/8] -> 203.0.113.1:[80-80] (tcp)},
nil, {[192.168.0.0/16] -> 203.0.113.2:[53-53] (udp)}",
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got := rulesToString(tt.rules)
+ if got != tt.want {
+ t.Errorf("rulesToString() = %q, want %q", got,
tt.want)
+ }
+ })
+ }
+}
+
+func TestRulesMapToString(t *testing.T) {
+ tests := []struct {
+ name string
+ rules map[*cloudstack.FirewallRule]bool
+ want string
+ }{
+ {
+ name: "empty map",
+ rules: map[*cloudstack.FirewallRule]bool{},
+ want: "",
+ },
+ {
+ name: "single rule",
+ rules: map[*cloudstack.FirewallRule]bool{
+ {
+ Protocol: "tcp",
+ Cidrlist: "10.0.0.0/8",
+ Ipaddress: "203.0.113.1",
+ Startport: 80,
+ Endport: 80,
+ }: true,
+ },
+ want: "{[10.0.0.0/8] -> 203.0.113.1:[80-80] (tcp)}",
+ },
+ {
+ name: "multiple rules",
+ rules: map[*cloudstack.FirewallRule]bool{
+ {
+ Protocol: "tcp",
+ Cidrlist: "10.0.0.0/8",
+ Ipaddress: "203.0.113.1",
+ Startport: 80,
+ Endport: 80,
+ }: true,
+ {
+ Protocol: "udp",
+ Cidrlist: "192.168.0.0/16",
+ Ipaddress: "203.0.113.2",
+ Startport: 53,
+ Endport: 53,
+ }: false,
+ {
+ Protocol: "icmp",
+ Cidrlist: "0.0.0.0/0",
+ Ipaddress: "203.0.113.3",
+ Icmptype: 8,
+ Icmpcode: 0,
+ }: true,
+ },
+ // Note: Map iteration order is non-deterministic, so
we need to check
+ // that all rules are present, not the exact order
+ want: "", // We'll check this differently
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got := rulesMapToString(tt.rules)
+
+ if tt.want == "" {
+ // For maps, we can't predict order, so check
that all rules are present
+ if len(tt.rules) == 0 {
+ if got != "" {
+ t.Errorf("rulesMapToString() =
%q, want empty string", got)
+ }
+ return
+ }
+
+ // Check that all rules are present in the
output
+ expectedRules := make([]string, 0,
len(tt.rules))
+ for rule := range tt.rules {
+ expectedRules = append(expectedRules,
ruleToString(rule))
+ }
+
+ // Split the output and check each rule is
present
+ if got != "" {
+ parts := strings.Split(got, ", ")
+ if len(parts) != len(expectedRules) {
+ t.Errorf("rulesMapToString()
returned %d rules, want %d", len(parts), len(expectedRules))
+ return
+ }
+
+ // Check that all expected rules are in
the output
+ for _, expectedRule := range
expectedRules {
+ found := false
+ for _, part := range parts {
+ if part == expectedRule
{
+ found = true
+ break
+ }
+ }
+ if !found {
+
t.Errorf("rulesMapToString() missing rule %q in output %q", expectedRule, got)
+ }
+ }
+ } else if len(expectedRules) > 0 {
+ t.Errorf("rulesMapToString() = empty
string, want rules to be present")
+ }
+ } else {
+ if got != tt.want {
+ t.Errorf("rulesMapToString() = %q, want
%q", got, tt.want)
+ }
+ }
+ })
+ }
+}
+
+func TestGetPublicIPAddress(t *testing.T) {
+ t.Run("IP found and allocated", func(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ t.Cleanup(ctrl.Finish)
+
+ mockAddress := cloudstack.NewMockAddressServiceIface(ctrl)
+ listParams := &cloudstack.ListPublicIpAddressesParams{}
+ resp := &cloudstack.ListPublicIpAddressesResponse{
+ Count: 1,
+ PublicIpAddresses: []*cloudstack.PublicIpAddress{
+ {
+ Id: "ip-123",
+ Ipaddress: "203.0.113.1",
+ Allocated: "2023-01-01T00:00:00+0000",
+ },
+ },
+ }
+
+ gomock.InOrder(
+
mockAddress.EXPECT().NewListPublicIpAddressesParams().Return(listParams),
+
mockAddress.EXPECT().ListPublicIpAddresses(gomock.Any()).Return(resp, nil),
+ )
+
+ lb := &loadBalancer{
+ CloudStackClient: &cloudstack.CloudStackClient{
+ Address: mockAddress,
+ },
+ }
+
+ err := lb.getPublicIPAddress("203.0.113.1")
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if lb.ipAddr != "203.0.113.1" {
+ t.Errorf("ipAddr = %q, want %q", lb.ipAddr,
"203.0.113.1")
+ }
+ if lb.ipAddrID != "ip-123" {
+ t.Errorf("ipAddrID = %q, want %q", lb.ipAddrID,
"ip-123")
+ }
+ })
+
+ t.Run("IP found but not allocated - associates", func(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ t.Cleanup(ctrl.Finish)
+
+ mockAddress := cloudstack.NewMockAddressServiceIface(ctrl)
+ mockNetwork := cloudstack.NewMockNetworkServiceIface(ctrl)
+ listParams := &cloudstack.ListPublicIpAddressesParams{}
+ resp := &cloudstack.ListPublicIpAddressesResponse{
+ Count: 1,
+ PublicIpAddresses: []*cloudstack.PublicIpAddress{
+ {
+ Id: "ip-123",
+ Ipaddress: "203.0.113.1",
+ Allocated: "",
+ },
+ },
+ }
+
+ networkResp := &cloudstack.Network{
+ Id: "net-123",
+ Vpcid: "",
+ Service: []cloudstack.NetworkServiceInternal{},
+ }
+
+ associateParams := &cloudstack.AssociateIpAddressParams{}
+ associateResp := &cloudstack.AssociateIpAddressResponse{
+ Id: "ip-123",
+ Ipaddress: "203.0.113.1",
+ }
+
+ gomock.InOrder(
+
mockAddress.EXPECT().NewListPublicIpAddressesParams().Return(listParams),
+
mockAddress.EXPECT().ListPublicIpAddresses(gomock.Any()).Return(resp, nil),
+ mockNetwork.EXPECT().GetNetworkByID("net-123",
gomock.Any()).Return(networkResp, 1, nil),
+
mockAddress.EXPECT().NewAssociateIpAddressParams().Return(associateParams),
+
mockAddress.EXPECT().AssociateIpAddress(gomock.Any()).Return(associateResp,
nil),
+ )
+
+ lb := &loadBalancer{
+ CloudStackClient: &cloudstack.CloudStackClient{
+ Address: mockAddress,
+ Network: mockNetwork,
+ },
+ networkID: "net-123",
+ ipAddr: "203.0.113.1",
+ }
+
+ err := lb.getPublicIPAddress("203.0.113.1")
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if lb.ipAddr != "203.0.113.1" {
+ t.Errorf("ipAddr = %q, want %q", lb.ipAddr,
"203.0.113.1")
+ }
+ if lb.ipAddrID != "ip-123" {
+ t.Errorf("ipAddrID = %q, want %q", lb.ipAddrID,
"ip-123")
+ }
+ })
+
+ t.Run("IP not found", func(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ t.Cleanup(ctrl.Finish)
+
+ mockAddress := cloudstack.NewMockAddressServiceIface(ctrl)
+ listParams := &cloudstack.ListPublicIpAddressesParams{}
+ resp := &cloudstack.ListPublicIpAddressesResponse{
+ Count: 0,
+ PublicIpAddresses: []*cloudstack.PublicIpAddress{},
+ }
+
+ gomock.InOrder(
+
mockAddress.EXPECT().NewListPublicIpAddressesParams().Return(listParams),
+
mockAddress.EXPECT().ListPublicIpAddresses(gomock.Any()).Return(resp, nil),
+ )
+
+ lb := &loadBalancer{
+ CloudStackClient: &cloudstack.CloudStackClient{
+ Address: mockAddress,
+ },
+ }
+
+ err := lb.getPublicIPAddress("203.0.113.1")
+ if err == nil {
+ t.Fatalf("expected error for IP not found")
+ }
+ if !strings.Contains(err.Error(), "could not find IP address") {
+ t.Errorf("error message = %q, want to contain 'could
not find IP address'", err.Error())
+ }
+ })
+
+ t.Run("multiple IPs found", func(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ t.Cleanup(ctrl.Finish)
+
+ mockAddress := cloudstack.NewMockAddressServiceIface(ctrl)
+ listParams := &cloudstack.ListPublicIpAddressesParams{}
+ resp := &cloudstack.ListPublicIpAddressesResponse{
+ Count: 2,
+ PublicIpAddresses: []*cloudstack.PublicIpAddress{
+ {Id: "ip-1", Ipaddress: "203.0.113.1"},
+ {Id: "ip-2", Ipaddress: "203.0.113.1"},
+ },
+ }
+
+ gomock.InOrder(
+
mockAddress.EXPECT().NewListPublicIpAddressesParams().Return(listParams),
+
mockAddress.EXPECT().ListPublicIpAddresses(gomock.Any()).Return(resp, nil),
+ )
+
+ lb := &loadBalancer{
+ CloudStackClient: &cloudstack.CloudStackClient{
+ Address: mockAddress,
+ },
+ }
+
+ err := lb.getPublicIPAddress("203.0.113.1")
+ if err == nil {
+ t.Fatalf("expected error for multiple IPs found")
+ }
+ if !strings.Contains(err.Error(), "Found 2 addresses") {
+ t.Errorf("error message = %q, want to contain 'Found 2
addresses'", err.Error())
+ }
+ })
+
+ t.Run("error retrieving IP", func(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ t.Cleanup(ctrl.Finish)
+
+ mockAddress := cloudstack.NewMockAddressServiceIface(ctrl)
+ listParams := &cloudstack.ListPublicIpAddressesParams{}
+ apiErr := fmt.Errorf("API error")
+
+ gomock.InOrder(
+
mockAddress.EXPECT().NewListPublicIpAddressesParams().Return(listParams),
+
mockAddress.EXPECT().ListPublicIpAddresses(gomock.Any()).Return(nil, apiErr),
+ )
+
+ lb := &loadBalancer{
+ CloudStackClient: &cloudstack.CloudStackClient{
+ Address: mockAddress,
+ },
+ }
+
+ err := lb.getPublicIPAddress("203.0.113.1")
+ if err == nil {
+ t.Fatalf("expected error")
+ }
+ if !strings.Contains(err.Error(), "error retrieving IP
address") {
+ t.Errorf("error message = %q, want to contain 'error
retrieving IP address'", err.Error())
+ }
+ })
+
+ t.Run("project ID handling", func(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ t.Cleanup(ctrl.Finish)
+
+ mockAddress := cloudstack.NewMockAddressServiceIface(ctrl)
+ listParams := &cloudstack.ListPublicIpAddressesParams{}
+ resp := &cloudstack.ListPublicIpAddressesResponse{
+ Count: 1,
+ PublicIpAddresses: []*cloudstack.PublicIpAddress{
+ {
+ Id: "ip-123",
+ Ipaddress: "203.0.113.1",
+ Allocated: "2023-01-01T00:00:00+0000",
+ },
+ },
+ }
+
+ gomock.InOrder(
+
mockAddress.EXPECT().NewListPublicIpAddressesParams().Return(listParams),
+
mockAddress.EXPECT().ListPublicIpAddresses(gomock.Any()).Return(resp, nil),
+ )
+
+ lb := &loadBalancer{
+ CloudStackClient: &cloudstack.CloudStackClient{
+ Address: mockAddress,
+ },
+ projectID: "proj-123",
+ }
+
+ err := lb.getPublicIPAddress("203.0.113.1")
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if lb.ipAddr != "203.0.113.1" {
+ t.Errorf("ipAddr = %q, want %q", lb.ipAddr,
"203.0.113.1")
+ }
+ if lb.ipAddrID != "ip-123" {
+ t.Errorf("ipAddrID = %q, want %q", lb.ipAddrID,
"ip-123")
+ }
+ })
+}
+
+func TestAssociatePublicIPAddress(t *testing.T) {
+ t.Run("associate IP for regular network", func(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ t.Cleanup(ctrl.Finish)
+
+ mockAddress := cloudstack.NewMockAddressServiceIface(ctrl)
+ mockNetwork := cloudstack.NewMockNetworkServiceIface(ctrl)
+ networkResp := &cloudstack.Network{
+ Id: "net-123",
+ Vpcid: "",
+ Service: []cloudstack.NetworkServiceInternal{},
+ }
+
+ associateParams := &cloudstack.AssociateIpAddressParams{}
+ associateResp := &cloudstack.AssociateIpAddressResponse{
+ Id: "ip-123",
+ Ipaddress: "203.0.113.1",
+ }
+
+ gomock.InOrder(
+ mockNetwork.EXPECT().GetNetworkByID("net-123",
gomock.Any()).Return(networkResp, 1, nil),
+
mockAddress.EXPECT().NewAssociateIpAddressParams().Return(associateParams),
+
mockAddress.EXPECT().AssociateIpAddress(gomock.Any()).Return(associateResp,
nil),
+ )
+
+ lb := &loadBalancer{
+ CloudStackClient: &cloudstack.CloudStackClient{
+ Address: mockAddress,
+ Network: mockNetwork,
+ },
+ networkID: "net-123",
+ }
+
+ err := lb.associatePublicIPAddress()
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if lb.ipAddr != "203.0.113.1" {
+ t.Errorf("ipAddr = %q, want %q", lb.ipAddr,
"203.0.113.1")
+ }
+ if lb.ipAddrID != "ip-123" {
+ t.Errorf("ipAddrID = %q, want %q", lb.ipAddrID,
"ip-123")
+ }
+ if !lb.ipAssociatedByController {
+ t.Errorf("ipAssociatedByController = false, want true")
+ }
+ })
+
+ t.Run("associate IP for VPC network", func(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ t.Cleanup(ctrl.Finish)
+
+ mockAddress := cloudstack.NewMockAddressServiceIface(ctrl)
+ mockNetwork := cloudstack.NewMockNetworkServiceIface(ctrl)
+ networkResp := &cloudstack.Network{
+ Id: "net-123",
+ Vpcid: "vpc-456",
+ Service: []cloudstack.NetworkServiceInternal{},
+ }
+
+ associateParams := &cloudstack.AssociateIpAddressParams{}
+ associateResp := &cloudstack.AssociateIpAddressResponse{
+ Id: "ip-123",
+ Ipaddress: "203.0.113.1",
+ }
+
+ gomock.InOrder(
+ mockNetwork.EXPECT().GetNetworkByID("net-123",
gomock.Any()).Return(networkResp, 1, nil),
+
mockAddress.EXPECT().NewAssociateIpAddressParams().Return(associateParams),
+
mockAddress.EXPECT().AssociateIpAddress(gomock.Any()).Return(associateResp,
nil),
+ )
+
+ lb := &loadBalancer{
+ CloudStackClient: &cloudstack.CloudStackClient{
+ Address: mockAddress,
+ Network: mockNetwork,
+ },
+ networkID: "net-123",
+ }
+
+ err := lb.associatePublicIPAddress()
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if lb.ipAddr != "203.0.113.1" {
+ t.Errorf("ipAddr = %q, want %q", lb.ipAddr,
"203.0.113.1")
+ }
+ if lb.ipAddrID != "ip-123" {
+ t.Errorf("ipAddrID = %q, want %q", lb.ipAddrID,
"ip-123")
+ }
+ if !lb.ipAssociatedByController {
+ t.Errorf("ipAssociatedByController = false, want true")
+ }
+ if lb.ipAddr != "203.0.113.1" {
+ t.Errorf("ipAddr = %q, want %q", lb.ipAddr,
"203.0.113.1")
+ }
+ if lb.ipAddrID != "ip-123" {
+ t.Errorf("ipAddrID = %q, want %q", lb.ipAddrID,
"ip-123")
+ }
+ if !lb.ipAssociatedByController {
+ t.Errorf("ipAssociatedByController = false, want true")
+ }
Review Comment:
Duplicate assertions detected. Lines 1364-1372 repeat the exact same checks
as lines 1355-1363. These duplicate assertions should be removed as they
provide no additional test value and make the test unnecessarily verbose.
```suggestion
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]