package oci import "testing" func TestNextSubnetIPv6CIDR(t *testing.T) { tests := []struct { name string vcnCidr string used []string want string wantErr bool }{ { name: "无占用取首个", vcnCidr: "2603:c020:e:de00::/56", want: "2603:c020:e:de00::/64", }, { name: "跳过已用索引", vcnCidr: "2603:c020:e:de00::/56", used: []string{"2603:c020:e:de00::/64", "2603:c020:e:de01::/64"}, want: "2603:c020:e:de02::/64", }, { name: "其他前缀的占用不影响", vcnCidr: "2603:c020:e:de00::/56", used: []string{"2603:c020:f:aa00::/64"}, want: "2603:c020:e:de00::/64", }, { name: "非法 VCN 前缀报错", vcnCidr: "not-a-cidr", wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := nextSubnetIPv6CIDR(tt.vcnCidr, tt.used) if (err != nil) != tt.wantErr { t.Fatalf("nextSubnetIPv6CIDR() error = %v, wantErr %v", err, tt.wantErr) } if !tt.wantErr && got != tt.want { t.Errorf("nextSubnetIPv6CIDR() = %q, want %q", got, tt.want) } }) } } func TestNextSubnetIPv6CIDRExhausted(t *testing.T) { used := make([]string, 0, 256) base := "2603:c020:e:de00::/56" for i := 0; i <= 255; i++ { cidr, err := nextSubnetIPv6CIDR(base, used) if err != nil { t.Fatalf("allocation %d failed: %v", i, err) } used = append(used, cidr) } if _, err := nextSubnetIPv6CIDR(base, used); err == nil { t.Error("257th allocation: got nil error, want exhausted failure") } } func TestSameIPv6(t *testing.T) { tests := []struct { name string a, b string want bool }{ {name: "完全一致", a: "2603:c020:e:de00::1", b: "2603:c020:e:de00::1", want: true}, {name: "大小写不敏感", a: "2603:C020:E:DE00::1", b: "2603:c020:e:de00::1", want: true}, {name: "缩写与全写等价", a: "2603:c020:e:de00:0:0:0:1", b: "2603:c020:e:de00::1", want: true}, {name: "不同地址", a: "2603:c020:e:de00::1", b: "2603:c020:e:de00::2", want: false}, {name: "非法输入回退字符串比较", a: "not-an-ip", b: "not-an-ip", want: true}, {name: "非法输入不相等", a: "not-an-ip", b: "2603:c020:e:de00::1", want: false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := sameIPv6(tt.a, tt.b); got != tt.want { t.Errorf("sameIPv6(%q, %q) = %v, want %v", tt.a, tt.b, got, tt.want) } }) } } func TestBuildRuleOptions(t *testing.T) { port := func(n int) *int { return &n } tests := []struct { name string rule SecurityRule wantTCP bool wantUDP bool wantICMP bool }{ {name: "TCP 端口", rule: SecurityRule{Protocol: "6", PortMin: port(22)}, wantTCP: true}, {name: "UDP 端口", rule: SecurityRule{Protocol: "17", PortMin: port(53), PortMax: port(53)}, wantUDP: true}, {name: "ICMP 类型", rule: SecurityRule{Protocol: "1", IcmpType: port(8)}, wantICMP: true}, {name: "ICMPv6 类型", rule: SecurityRule{Protocol: "58", IcmpType: port(128)}, wantICMP: true}, {name: "all 无选项", rule: SecurityRule{Protocol: "all"}}, {name: "TCP 无端口无选项", rule: SecurityRule{Protocol: "6"}}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tcp, udp, icmp := buildRuleOptions(tt.rule) if (tcp != nil) != tt.wantTCP { t.Errorf("tcp options = %v, want present=%v", tcp, tt.wantTCP) } if (udp != nil) != tt.wantUDP { t.Errorf("udp options = %v, want present=%v", udp, tt.wantUDP) } if (icmp != nil) != tt.wantICMP { t.Errorf("icmp options = %v, want present=%v", icmp, tt.wantICMP) } if tt.wantTCP && tt.rule.PortMax == nil { if got, want := *tcp.DestinationPortRange.Max, *tt.rule.PortMin; got != want { t.Errorf("port max = %d, want fallback to min %d", got, want) } } }) } }