-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a5195ef
commit 0cbdf16
Showing
18 changed files
with
1,391 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
//go:build !integration | ||
// +build !integration | ||
|
||
package v1_test | ||
|
||
import ( | ||
"fmt" | ||
"math" | ||
"net" | ||
|
||
ipamv1 "go.anx.io/go-anxcloud/pkg/apis/ipam/v1" | ||
testutils "go.anx.io/go-anxcloud/pkg/utils/test" | ||
|
||
. "github.com/onsi/gomega" | ||
. "github.com/onsi/gomega/ghttp" | ||
) | ||
|
||
const ( | ||
mockAddressIdentifier = "address-foobarbaz4223691337" | ||
) | ||
|
||
func mockBasicAddressResponseBody(p ipamv1.Prefix, desc string, ip string) map[string]interface{} { | ||
ret := map[string]interface{}{ | ||
"identifier": testutils.TestResourceName(), | ||
"name": ip, | ||
"description_customer": desc, | ||
"version": p.Version, | ||
"role_text": "Default", | ||
"status": "Active", | ||
"prefix": p.Identifier, | ||
} | ||
|
||
if len(p.VLANs) == 1 { | ||
ret["vlan"] = p.VLANs[0].Identifier | ||
} | ||
|
||
return ret | ||
} | ||
|
||
func mockAddressResponseBody(p ipamv1.Prefix, desc string, ip net.IP) map[string]interface{} { | ||
status := "Pending" | ||
|
||
if mockPrefixGetDeleting { | ||
status = "Marked for deletion" | ||
} else if mockPrefixGetActive { | ||
status = "Active" | ||
} | ||
|
||
ret := mockBasicAddressResponseBody(p, desc, ip.String()) | ||
ret["identifier"] = mockAddressIdentifier | ||
ret["status"] = status | ||
|
||
return ret | ||
} | ||
|
||
func prepareAddressCreate(p ipamv1.Prefix, desc string, ip net.IP) { | ||
exp := map[string]interface{}{ | ||
"name": ip, | ||
"description_customer": desc, | ||
"version": p.Version, | ||
"prefix": p.Identifier, | ||
} | ||
|
||
if len(p.VLANs) == 1 { | ||
exp["vlan"] = p.VLANs[0].Identifier | ||
} | ||
|
||
mockServer.AppendHandlers(CombineHandlers( | ||
VerifyRequest("POST", "/api/ipam/v1/address.json"), | ||
VerifyJSONRepresenting(exp), | ||
RespondWithJSONEncoded(200, mockAddressResponseBody(p, desc, ip)), | ||
)) | ||
} | ||
|
||
func prepareAddressGet(p ipamv1.Prefix, desc string, ip net.IP) { | ||
mockServer.AppendHandlers(CombineHandlers( | ||
VerifyRequest("GET", "/api/ipam/v1/address.json/"+mockAddressIdentifier), | ||
RespondWithJSONEncoded(200, mockAddressResponseBody(p, desc, ip)), | ||
)) | ||
} | ||
|
||
func prepareAddressList(p ipamv1.Prefix, shouldEmpty bool, desc string, ip net.IP) { | ||
baseIP, _, err := net.ParseCIDR(p.Name) | ||
Expect(err).NotTo(HaveOccurred(), "expected a parsable prefix") | ||
|
||
var mockAddresses []map[string]interface{} | ||
|
||
if !shouldEmpty { | ||
if p.Version == ipamv1.FamilyIPv6 { | ||
// this would run out of memory very badly | ||
panic("never ever try to have an IPv6 prefix that is _not empty_") | ||
} | ||
|
||
if p.Netmask < 24 { | ||
panic("e2e mocks only supports netmask >= 24") | ||
} | ||
|
||
numAddresses := int(math.Exp2(float64(32 - p.Netmask))) | ||
mockAddresses = make([]map[string]interface{}, numAddresses) | ||
|
||
for i := range mockAddresses { | ||
ip := make(net.IP, len(baseIP)) | ||
copy(ip, baseIP) | ||
ip[len(ip)-1] += byte(i) | ||
mockAddresses[i] = mockBasicAddressResponseBody(p, testutils.TestResourceName(), ip.String()) | ||
} | ||
|
||
ipIdx := ip[len(ip)-1] - baseIP[len(baseIP)-1] | ||
mockAddresses[ipIdx] = mockAddressResponseBody(p, desc, ip) | ||
|
||
} else { | ||
mockAddresses = make([]map[string]interface{}, 0, 4) | ||
mockAddresses = append(mockAddresses, mockBasicAddressResponseBody(p, "Network address", baseIP.String())) | ||
|
||
gatewayIP := make(net.IP, len(baseIP)) | ||
copy(gatewayIP, baseIP) | ||
gatewayIP[len(gatewayIP)-1]++ | ||
mockAddresses = append(mockAddresses, mockBasicAddressResponseBody(p, "Gateway", gatewayIP.String())) | ||
|
||
mockAddresses = append(mockAddresses, mockAddressResponseBody(p, desc, ip)) | ||
|
||
if p.Version == ipamv1.FamilyIPv4 { | ||
broadcastIP := make(net.IP, len(baseIP)) | ||
copy(broadcastIP, baseIP) | ||
broadcastIP[len(broadcastIP)-1] += 7 // let's statically calc for a /29, good enough for the mock | ||
mockAddresses = append(mockAddresses, mockBasicAddressResponseBody(p, "Broadcast", broadcastIP.String())) | ||
} | ||
} | ||
|
||
pageCount := len(mockAddresses) / 10 | ||
if pageCount*10 < len(mockAddresses) { | ||
pageCount++ | ||
} | ||
|
||
Expect(pageCount).To(BeNumerically(">=", 1)) | ||
|
||
expectedQuery := fmt.Sprintf( | ||
"prefix=%v&version=%v&private=%v", | ||
p.Identifier, p.Version, p.Type == ipamv1.AddressSpacePrivate, | ||
) | ||
|
||
for i := 0; i <= pageCount; i++ { | ||
pageQuery := fmt.Sprintf("%v&page=%v&limit=10", expectedQuery, i+1) | ||
|
||
var data []map[string]interface{} | ||
|
||
if i < pageCount { | ||
firstIdx := 10 * i | ||
count := 10 | ||
|
||
if firstIdx+count > len(mockAddresses) { | ||
count = len(mockAddresses) - firstIdx | ||
} | ||
|
||
data = mockAddresses[firstIdx:count] | ||
} else { | ||
data = make([]map[string]interface{}, 0) | ||
} | ||
|
||
mockServer.AppendHandlers(CombineHandlers( | ||
VerifyRequest("GET", "/api/ipam/v1/address/filtered.json", pageQuery), | ||
RespondWithJSONEncoded(200, map[string]interface{}{ | ||
"page": i + 1, | ||
"total_pages": pageCount, | ||
"total_items": len(mockAddresses), | ||
"limit": 10, | ||
"data": data, | ||
}), | ||
)) | ||
} | ||
} | ||
|
||
func prepareAddressUpdate(p ipamv1.Prefix, desc string, ip net.IP) { | ||
mockServer.AppendHandlers(CombineHandlers( | ||
VerifyRequest("PUT", "/api/ipam/v1/address.json/"+mockAddressIdentifier), | ||
VerifyJSONRepresenting(map[string]interface{}{ | ||
"identifier": mockAddressIdentifier, | ||
"description_customer": desc, | ||
}), | ||
RespondWithJSONEncoded(200, mockAddressResponseBody(p, desc, ip)), | ||
)) | ||
} | ||
|
||
func prepareAddressDelete(p ipamv1.Prefix, desc string, ip net.IP) { | ||
mockServer.AppendHandlers(CombineHandlers( | ||
VerifyRequest("DELETE", "/api/ipam/v1/address.json/"+mockAddressIdentifier), | ||
RespondWithJSONEncoded(200, mockAddressResponseBody(p, desc, ip)), | ||
)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
package v1_test | ||
|
||
import ( | ||
"context" | ||
"net" | ||
|
||
"go.anx.io/go-anxcloud/pkg/api" | ||
"go.anx.io/go-anxcloud/pkg/api/types" | ||
ipamv1 "go.anx.io/go-anxcloud/pkg/apis/ipam/v1" | ||
testutils "go.anx.io/go-anxcloud/pkg/utils/test" | ||
|
||
. "github.com/onsi/ginkgo/v2" | ||
. "github.com/onsi/gomega" | ||
) | ||
|
||
func testAddress(c *api.API, shouldBeEmpty bool, p *ipamv1.Prefix) { | ||
var apiClient api.API | ||
var prefix ipamv1.Prefix | ||
|
||
BeforeEach(func() { | ||
apiClient = *c | ||
prefix = *p | ||
}) | ||
|
||
testForIP := func(ip *net.IP) { | ||
var address ipamv1.Address | ||
|
||
BeforeAll(func() { | ||
address = ipamv1.Address{ | ||
Name: ip.String(), | ||
DescriptionCustomer: testutils.TestResourceName(), | ||
Version: prefix.Version, | ||
Prefix: prefix, | ||
} | ||
|
||
if len(prefix.VLANs) == 1 { | ||
address.VLAN = prefix.VLANs[0] | ||
} | ||
}) | ||
|
||
if shouldBeEmpty { | ||
It("creates the test address", func() { | ||
prepareAddressCreate(prefix, address.DescriptionCustomer, *ip) | ||
|
||
err := apiClient.Create(context.TODO(), &address) | ||
Expect(err).NotTo(HaveOccurred()) | ||
}) | ||
} | ||
|
||
It("finds the test address", func() { | ||
prepareAddressList(prefix, shouldBeEmpty, address.DescriptionCustomer, *ip) | ||
|
||
var oc types.ObjectChannel | ||
err := apiClient.List( | ||
context.TODO(), | ||
&ipamv1.Address{ | ||
Prefix: prefix, | ||
Version: prefix.Version, | ||
Type: prefix.Type, | ||
}, | ||
api.ObjectChannel(&oc), | ||
) | ||
Expect(err).NotTo(HaveOccurred()) | ||
|
||
addressCount := 0 | ||
for retriever := range oc { | ||
var addr ipamv1.Address | ||
err := retriever(&addr) | ||
Expect(err).NotTo(HaveOccurred()) | ||
|
||
addressCount++ | ||
|
||
if net.ParseIP(addr.Name).Equal(*ip) { | ||
address.Identifier = addr.Identifier | ||
} | ||
} | ||
|
||
// network address, gateway and our test IP | ||
expectedIPs := 3 | ||
|
||
if prefix.Version == ipamv1.FamilyIPv4 { | ||
// for IPv4 we additionally get the broadcast address | ||
expectedIPs++ | ||
|
||
if !shouldBeEmpty { | ||
// we test with /29 prefixes, so there should be 8 addresses when not created empty | ||
expectedIPs = 8 | ||
} | ||
} | ||
|
||
Expect(addressCount).To(Equal(expectedIPs)) | ||
}) | ||
|
||
It("retrieves the test address", func() { | ||
prepareAddressGet(prefix, address.DescriptionCustomer, *ip) | ||
|
||
err := apiClient.Get(context.TODO(), &address) | ||
Expect(err).NotTo(HaveOccurred()) | ||
|
||
Expect(address.Name).To(Equal(ip.String())) | ||
}) | ||
|
||
It("updates the test address description", func() { | ||
address.DescriptionCustomer += " - Updated!" | ||
prepareAddressUpdate(prefix, address.DescriptionCustomer, *ip) | ||
|
||
err := apiClient.Update(context.TODO(), &ipamv1.Address{ | ||
Identifier: address.Identifier, | ||
DescriptionCustomer: address.DescriptionCustomer, | ||
}) | ||
Expect(err).NotTo(HaveOccurred()) | ||
}) | ||
|
||
It("retrieves the test address with the new description", func() { | ||
prepareAddressGet(prefix, address.DescriptionCustomer, *ip) | ||
|
||
err := apiClient.Get(context.TODO(), &address) | ||
Expect(err).NotTo(HaveOccurred()) | ||
|
||
Expect(address.Name).To(Equal(ip.String())) | ||
}) | ||
|
||
It("deletes the test address", func() { | ||
prepareAddressDelete(prefix, address.DescriptionCustomer, *ip) | ||
|
||
err := apiClient.Destroy(context.TODO(), &address) | ||
Expect(err).NotTo(HaveOccurred()) | ||
}) | ||
} | ||
|
||
Context("fixed address", Ordered, func() { | ||
ip := new(net.IP) | ||
|
||
BeforeAll(func() { | ||
i, _, err := net.ParseCIDR(prefix.Name) | ||
Expect(err).NotTo(HaveOccurred(), "expected parsable prefix") | ||
|
||
i[len(i)-1] += 3 | ||
*ip = i | ||
}) | ||
|
||
testForIP(ip) | ||
}) | ||
} |
Oops, something went wrong.