unit and acceptance tests
diff --git a/acceptance/openstack/networking/v2/port_test.go b/acceptance/openstack/networking/v2/port_test.go
index 7f22dbd..03e8e27 100644
--- a/acceptance/openstack/networking/v2/port_test.go
+++ b/acceptance/openstack/networking/v2/port_test.go
@@ -82,7 +82,7 @@
th.AssertNoErr(t, err)
for _, p := range portList {
- t.Logf("Port: ID [%s] Name [%s] Status [%d] MAC addr [%s] Fixed IPs [%#v] Security groups [%#v]",
+ t.Logf("Port: ID [%s] Name [%s] Status [%s] MAC addr [%s] Fixed IPs [%#v] Security groups [%#v]",
p.ID, p.Name, p.Status, p.MACAddress, p.FixedIPs, p.SecurityGroups)
}
diff --git a/acceptance/rackspace/networking/v2/common.go b/acceptance/rackspace/networking/v2/common.go
new file mode 100644
index 0000000..8170418
--- /dev/null
+++ b/acceptance/rackspace/networking/v2/common.go
@@ -0,0 +1,39 @@
+package v2
+
+import (
+ "os"
+ "testing"
+
+ "github.com/rackspace/gophercloud"
+ "github.com/rackspace/gophercloud/rackspace"
+ th "github.com/rackspace/gophercloud/testhelper"
+)
+
+var Client *gophercloud.ServiceClient
+
+func NewClient() (*gophercloud.ServiceClient, error) {
+ opts, err := rackspace.AuthOptionsFromEnv()
+ if err != nil {
+ return nil, err
+ }
+
+ provider, err := rackspace.AuthenticatedClient(opts)
+ if err != nil {
+ return nil, err
+ }
+
+ return rackspace.NewNetworkV2(provider, gophercloud.EndpointOpts{
+ Name: "cloudNetworks",
+ Region: os.Getenv("RS_REGION"),
+ })
+}
+
+func Setup(t *testing.T) {
+ client, err := NewClient()
+ th.AssertNoErr(t, err)
+ Client = client
+}
+
+func Teardown() {
+ Client = nil
+}
diff --git a/acceptance/rackspace/networking/v2/network_test.go b/acceptance/rackspace/networking/v2/network_test.go
new file mode 100644
index 0000000..3862123
--- /dev/null
+++ b/acceptance/rackspace/networking/v2/network_test.go
@@ -0,0 +1,65 @@
+// +build acceptance networking
+
+package v2
+
+import (
+ "strconv"
+ "testing"
+
+ os "github.com/rackspace/gophercloud/openstack/networking/v2/networks"
+ "github.com/rackspace/gophercloud/pagination"
+ "github.com/rackspace/gophercloud/rackspace/networking/v2/networks"
+ th "github.com/rackspace/gophercloud/testhelper"
+)
+
+func TestNetworkCRUDOperations(t *testing.T) {
+ Setup(t)
+ defer Teardown()
+
+ // Create a network
+ n, err := networks.Create(Client, os.CreateOpts{Name: "sample_network", AdminStateUp: os.Up}).Extract()
+ th.AssertNoErr(t, err)
+ defer networks.Delete(Client, n.ID)
+ th.AssertEquals(t, "sample_network", n.Name)
+ th.AssertEquals(t, true, n.AdminStateUp)
+ networkID := n.ID
+
+ // List networks
+ pager := networks.List(Client, os.ListOpts{Limit: 2})
+ err = pager.EachPage(func(page pagination.Page) (bool, error) {
+ t.Logf("--- Page ---")
+
+ networkList, err := os.ExtractNetworks(page)
+ th.AssertNoErr(t, err)
+
+ for _, n := range networkList {
+ t.Logf("Network: ID [%s] Name [%s] Status [%s] Is shared? [%s]",
+ n.ID, n.Name, n.Status, strconv.FormatBool(n.Shared))
+ }
+
+ return true, nil
+ })
+ th.CheckNoErr(t, err)
+
+ // Get a network
+ if networkID == "" {
+ t.Fatalf("In order to retrieve a network, the NetworkID must be set")
+ }
+ n, err = networks.Get(Client, networkID).Extract()
+ th.AssertNoErr(t, err)
+ th.AssertEquals(t, "ACTIVE", n.Status)
+ th.AssertDeepEquals(t, []string{}, n.Subnets)
+ th.AssertEquals(t, "sample_network", n.Name)
+ th.AssertEquals(t, true, n.AdminStateUp)
+ th.AssertEquals(t, false, n.Shared)
+ th.AssertEquals(t, networkID, n.ID)
+
+ // Update network
+ n, err = networks.Update(Client, networkID, os.UpdateOpts{Name: "new_network_name"}).Extract()
+ th.AssertNoErr(t, err)
+ th.AssertEquals(t, "new_network_name", n.Name)
+
+ // Delete network
+ res := networks.Delete(Client, networkID)
+ th.AssertNoErr(t, res.Err)
+}
diff --git a/acceptance/rackspace/networking/v2/port_test.go b/acceptance/rackspace/networking/v2/port_test.go
new file mode 100644
index 0000000..3c42bb2
--- /dev/null
+++ b/acceptance/rackspace/networking/v2/port_test.go
@@ -0,0 +1,116 @@
+// +build acceptance networking
+
+package v2
+
+import (
+ "testing"
+
+ osNetworks "github.com/rackspace/gophercloud/openstack/networking/v2/networks"
+ osPorts "github.com/rackspace/gophercloud/openstack/networking/v2/ports"
+ osSubnets "github.com/rackspace/gophercloud/openstack/networking/v2/subnets"
+ "github.com/rackspace/gophercloud/pagination"
+ "github.com/rackspace/gophercloud/rackspace/networking/v2/networks"
+ "github.com/rackspace/gophercloud/rackspace/networking/v2/ports"
+ "github.com/rackspace/gophercloud/rackspace/networking/v2/subnets"
+ th "github.com/rackspace/gophercloud/testhelper"
+)
+
+func TestPortCRUD(t *testing.T) {
+ Setup(t)
+ defer Teardown()
+
+ // Setup network
+ t.Log("Setting up network")
+ networkID, err := createNetwork()
+ th.AssertNoErr(t, err)
+ defer networks.Delete(Client, networkID)
+
+ // Setup subnet
+ t.Logf("Setting up subnet on network %s", networkID)
+ subnetID, err := createSubnet(networkID)
+ th.AssertNoErr(t, err)
+ defer subnets.Delete(Client, subnetID)
+
+ // Create port
+ t.Logf("Create port based on subnet %s", subnetID)
+ portID := createPort(t, networkID, subnetID)
+
+ // List ports
+ t.Logf("Listing all ports")
+ listPorts(t)
+
+ // Get port
+ if portID == "" {
+ t.Fatalf("In order to retrieve a port, the portID must be set")
+ }
+ p, err := ports.Get(Client, portID).Extract()
+ th.AssertNoErr(t, err)
+ th.AssertEquals(t, portID, p.ID)
+
+ // Update port
+ p, err = ports.Update(Client, portID, osPorts.UpdateOpts{Name: "new_port_name"}).Extract()
+ th.AssertNoErr(t, err)
+ th.AssertEquals(t, "new_port_name", p.Name)
+
+ // Delete port
+ res := ports.Delete(Client, portID)
+ th.AssertNoErr(t, res.Err)
+}
+
+func createPort(t *testing.T, networkID, subnetID string) string {
+ enable := true
+ opts := osPorts.CreateOpts{
+ NetworkID: networkID,
+ Name: "my_port",
+ AdminStateUp: &enable,
+ FixedIPs: []osPorts.IP{osPorts.IP{SubnetID: subnetID}},
+ }
+ p, err := ports.Create(Client, opts).Extract()
+ th.AssertNoErr(t, err)
+ th.AssertEquals(t, networkID, p.NetworkID)
+ th.AssertEquals(t, "my_port", p.Name)
+ th.AssertEquals(t, true, p.AdminStateUp)
+
+ return p.ID
+}
+
+func listPorts(t *testing.T) {
+ count := 0
+ pager := ports.List(Client, osPorts.ListOpts{})
+ err := pager.EachPage(func(page pagination.Page) (bool, error) {
+ count++
+ t.Logf("--- Page ---")
+
+ portList, err := osPorts.ExtractPorts(page)
+ th.AssertNoErr(t, err)
+
+ for _, p := range portList {
+ t.Logf("Port: ID [%s] Name [%s] Status [%s] MAC addr [%s] Fixed IPs [%#v] Security groups [%#v]",
+ p.ID, p.Name, p.Status, p.MACAddress, p.FixedIPs, p.SecurityGroups)
+ }
+
+ return true, nil
+ })
+
+ th.CheckNoErr(t, err)
+
+ if count == 0 {
+ t.Logf("No pages were iterated over when listing ports")
+ }
+}
+
+func createNetwork() (string, error) {
+ res, err := networks.Create(Client, osNetworks.CreateOpts{Name: "tmp_network", AdminStateUp: osNetworks.Up}).Extract()
+ return res.ID, err
+}
+
+func createSubnet(networkID string) (string, error) {
+ s, err := subnets.Create(Client, osSubnets.CreateOpts{
+ NetworkID: networkID,
+ CIDR: "192.168.199.0/24",
+ IPVersion: osSubnets.IPv4,
+ Name: "my_subnet",
+ EnableDHCP: osSubnets.Down,
+ }).Extract()
+ return s.ID, err
+}
diff --git a/acceptance/rackspace/networking/v2/subnet_test.go b/acceptance/rackspace/networking/v2/subnet_test.go
new file mode 100644
index 0000000..c401432
--- /dev/null
+++ b/acceptance/rackspace/networking/v2/subnet_test.go
@@ -0,0 +1,84 @@
+// +build acceptance networking
+
+package v2
+
+import (
+ "testing"
+
+ osNetworks "github.com/rackspace/gophercloud/openstack/networking/v2/networks"
+ osSubnets "github.com/rackspace/gophercloud/openstack/networking/v2/subnets"
+ "github.com/rackspace/gophercloud/pagination"
+ "github.com/rackspace/gophercloud/rackspace/networking/v2/networks"
+ "github.com/rackspace/gophercloud/rackspace/networking/v2/subnets"
+ th "github.com/rackspace/gophercloud/testhelper"
+)
+
+func TestListSubnets(t *testing.T) {
+ Setup(t)
+ defer Teardown()
+
+ pager := subnets.List(Client, osSubnets.ListOpts{Limit: 2})
+ err := pager.EachPage(func(page pagination.Page) (bool, error) {
+ t.Logf("--- Page ---")
+
+ subnetList, err := osSubnets.ExtractSubnets(page)
+ th.AssertNoErr(t, err)
+
+ for _, s := range subnetList {
+ t.Logf("Subnet: ID [%s] Name [%s] IP Version [%d] CIDR [%s] GatewayIP [%s]",
+ s.ID, s.Name, s.IPVersion, s.CIDR, s.GatewayIP)
+ }
+
+ return true, nil
+ })
+ th.CheckNoErr(t, err)
+}
+
+func TestSubnetCRUD(t *testing.T) {
+ Setup(t)
+ defer Teardown()
+
+ // Setup network
+ t.Log("Setting up network")
+ n, err := networks.Create(Client, osNetworks.CreateOpts{Name: "tmp_network", AdminStateUp: osNetworks.Up}).Extract()
+ th.AssertNoErr(t, err)
+ networkID := n.ID
+ defer networks.Delete(Client, networkID)
+
+ // Create subnet
+ t.Log("Create subnet")
+ enable := false
+ opts := osSubnets.CreateOpts{
+ NetworkID: networkID,
+ CIDR: "192.168.199.0/24",
+ IPVersion: osSubnets.IPv4,
+ Name: "my_subnet",
+ EnableDHCP: &enable,
+ }
+ s, err := subnets.Create(Client, opts).Extract()
+ th.AssertNoErr(t, err)
+
+ th.AssertEquals(t, networkID, s.NetworkID)
+ th.AssertEquals(t, "192.168.199.0/24", s.CIDR)
+ th.AssertEquals(t, 4, s.IPVersion)
+ th.AssertEquals(t, "my_subnet", s.Name)
+ th.AssertEquals(t, false, s.EnableDHCP)
+ subnetID := s.ID
+
+ // Get subnet
+ t.Log("Getting subnet")
+ s, err = subnets.Get(Client, subnetID).Extract()
+ th.AssertNoErr(t, err)
+ th.AssertEquals(t, subnetID, s.ID)
+
+ // Update subnet
+ t.Log("Update subnet")
+ s, err = subnets.Update(Client, subnetID, osSubnets.UpdateOpts{Name: "new_subnet_name"}).Extract()
+ th.AssertNoErr(t, err)
+ th.AssertEquals(t, "new_subnet_name", s.Name)
+
+ // Delete subnet
+ t.Log("Delete subnet")
+ res := subnets.Delete(Client, subnetID)
+ th.AssertNoErr(t, res.Err)
+}
diff --git a/rackspace/client.go b/rackspace/client.go
index 65b547b..7421ff0 100644
--- a/rackspace/client.go
+++ b/rackspace/client.go
@@ -165,3 +165,14 @@
}
return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
}
+
+// NewNetworkV2 creates a ServiceClient that can be used to access the Rackspace
+// Networking v2 API.
+func NewNetworkV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
+ eo.ApplyDefaults("network")
+ url, err := client.EndpointLocator(eo)
+ if err != nil {
+ return nil, err
+ }
+ return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
+}
diff --git a/rackspace/networking/v2/common/common_tests.go b/rackspace/networking/v2/common/common_tests.go
new file mode 100644
index 0000000..129cd63
--- /dev/null
+++ b/rackspace/networking/v2/common/common_tests.go
@@ -0,0 +1,12 @@
+package common
+
+import (
+ "github.com/rackspace/gophercloud"
+ "github.com/rackspace/gophercloud/testhelper/client"
+)
+
+const TokenID = client.TokenID
+
+func ServiceClient() *gophercloud.ServiceClient {
+ return client.ServiceClient()
+}
diff --git a/rackspace/networking/v2/networks/delegate_test.go b/rackspace/networking/v2/networks/delegate_test.go
new file mode 100644
index 0000000..f51c732
--- /dev/null
+++ b/rackspace/networking/v2/networks/delegate_test.go
@@ -0,0 +1,276 @@
+package networks
+
+import (
+ "fmt"
+ "net/http"
+ "testing"
+
+ os "github.com/rackspace/gophercloud/openstack/networking/v2/networks"
+ "github.com/rackspace/gophercloud/pagination"
+ fake "github.com/rackspace/gophercloud/rackspace/networking/v2/common"
+ th "github.com/rackspace/gophercloud/testhelper"
+)
+
+func TestList(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ th.Mux.HandleFunc("/networks", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "GET")
+ th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
+
+ w.Header().Add("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+
+ fmt.Fprintf(w, `
+{
+ "networks": [
+ {
+ "status": "ACTIVE",
+ "subnets": [
+ "54d6f61d-db07-451c-9ab3-b9609b6b6f0b"
+ ],
+ "name": "private-network",
+ "admin_state_up": true,
+ "tenant_id": "4fd44f30292945e481c7b8a0c8908869",
+ "shared": true,
+ "id": "d32019d3-bc6e-4319-9c1d-6722fc136a22"
+ },
+ {
+ "status": "ACTIVE",
+ "subnets": [
+ "08eae331-0402-425a-923c-34f7cfe39c1b"
+ ],
+ "name": "private",
+ "admin_state_up": true,
+ "tenant_id": "26a7980765d0414dbc1fc1f88cdb7e6e",
+ "shared": true,
+ "id": "db193ab3-96e3-4cb3-8fc5-05f4296d0324"
+ }
+ ]
+}
+ `)
+ })
+
+ client := fake.ServiceClient()
+ count := 0
+
+ List(client, os.ListOpts{}).EachPage(func(page pagination.Page) (bool, error) {
+ count++
+ actual, err := os.ExtractNetworks(page)
+ if err != nil {
+ t.Errorf("Failed to extract networks: %v", err)
+ return false, err
+ }
+
+ expected := []os.Network{
+ os.Network{
+ Status: "ACTIVE",
+ Subnets: []string{"54d6f61d-db07-451c-9ab3-b9609b6b6f0b"},
+ Name: "private-network",
+ AdminStateUp: true,
+ TenantID: "4fd44f30292945e481c7b8a0c8908869",
+ Shared: true,
+ ID: "d32019d3-bc6e-4319-9c1d-6722fc136a22",
+ },
+ os.Network{
+ Status: "ACTIVE",
+ Subnets: []string{"08eae331-0402-425a-923c-34f7cfe39c1b"},
+ Name: "private",
+ AdminStateUp: true,
+ TenantID: "26a7980765d0414dbc1fc1f88cdb7e6e",
+ Shared: true,
+ ID: "db193ab3-96e3-4cb3-8fc5-05f4296d0324",
+ },
+ }
+
+ th.CheckDeepEquals(t, expected, actual)
+
+ return true, nil
+ })
+
+ if count != 1 {
+ t.Errorf("Expected 1 page, got %d", count)
+ }
+}
+
+func TestGet(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ th.Mux.HandleFunc("/networks/d32019d3-bc6e-4319-9c1d-6722fc136a22", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "GET")
+ th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
+
+ w.Header().Add("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+
+ fmt.Fprintf(w, `
+{
+ "network": {
+ "status": "ACTIVE",
+ "subnets": [
+ "54d6f61d-db07-451c-9ab3-b9609b6b6f0b"
+ ],
+ "name": "private-network",
+ "admin_state_up": true,
+ "tenant_id": "4fd44f30292945e481c7b8a0c8908869",
+ "shared": true,
+ "id": "d32019d3-bc6e-4319-9c1d-6722fc136a22"
+ }
+}
+ `)
+ })
+
+ n, err := Get(fake.ServiceClient(), "d32019d3-bc6e-4319-9c1d-6722fc136a22").Extract()
+ th.AssertNoErr(t, err)
+
+ th.AssertEquals(t, n.Status, "ACTIVE")
+ th.AssertDeepEquals(t, n.Subnets, []string{"54d6f61d-db07-451c-9ab3-b9609b6b6f0b"})
+ th.AssertEquals(t, n.Name, "private-network")
+ th.AssertEquals(t, n.AdminStateUp, true)
+ th.AssertEquals(t, n.TenantID, "4fd44f30292945e481c7b8a0c8908869")
+ th.AssertEquals(t, n.Shared, true)
+ th.AssertEquals(t, n.ID, "d32019d3-bc6e-4319-9c1d-6722fc136a22")
+}
+
+func TestCreate(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ th.Mux.HandleFunc("/networks", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "POST")
+ th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
+ th.TestHeader(t, r, "Content-Type", "application/json")
+ th.TestHeader(t, r, "Accept", "application/json")
+ th.TestJSONRequest(t, r, `
+{
+ "network": {
+ "name": "sample_network",
+ "admin_state_up": true
+ }
+}
+ `)
+
+ w.Header().Add("Content-Type", "application/json")
+ w.WriteHeader(http.StatusCreated)
+
+ fmt.Fprintf(w, `
+{
+ "network": {
+ "status": "ACTIVE",
+ "subnets": [],
+ "name": "net1",
+ "admin_state_up": true,
+ "tenant_id": "9bacb3c5d39d41a79512987f338cf177",
+ "shared": false,
+ "id": "4e8e5957-649f-477b-9e5b-f1f75b21c03c"
+ }
+}
+ `)
+ })
+
+ iTrue := true
+ options := os.CreateOpts{Name: "sample_network", AdminStateUp: &iTrue}
+ n, err := Create(fake.ServiceClient(), options).Extract()
+ th.AssertNoErr(t, err)
+
+ th.AssertEquals(t, n.Status, "ACTIVE")
+ th.AssertDeepEquals(t, n.Subnets, []string{})
+ th.AssertEquals(t, n.Name, "net1")
+ th.AssertEquals(t, n.AdminStateUp, true)
+ th.AssertEquals(t, n.TenantID, "9bacb3c5d39d41a79512987f338cf177")
+ th.AssertEquals(t, n.Shared, false)
+ th.AssertEquals(t, n.ID, "4e8e5957-649f-477b-9e5b-f1f75b21c03c")
+}
+
+func TestCreateWithOptionalFields(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ th.Mux.HandleFunc("/networks", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "POST")
+ th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
+ th.TestHeader(t, r, "Content-Type", "application/json")
+ th.TestHeader(t, r, "Accept", "application/json")
+ th.TestJSONRequest(t, r, `
+{
+ "network": {
+ "name": "sample_network",
+ "admin_state_up": true,
+ "shared": true,
+ "tenant_id": "12345"
+ }
+}
+ `)
+
+ w.WriteHeader(http.StatusCreated)
+ })
+
+ iTrue := true
+ options := os.CreateOpts{Name: "sample_network", AdminStateUp: &iTrue, Shared: &iTrue, TenantID: "12345"}
+ _, err := Create(fake.ServiceClient(), options).Extract()
+ th.AssertNoErr(t, err)
+}
+
+func TestUpdate(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ th.Mux.HandleFunc("/networks/4e8e5957-649f-477b-9e5b-f1f75b21c03c", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "PUT")
+ th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
+ th.TestHeader(t, r, "Content-Type", "application/json")
+ th.TestHeader(t, r, "Accept", "application/json")
+ th.TestJSONRequest(t, r, `
+{
+ "network": {
+ "name": "new_network_name",
+ "admin_state_up": false,
+ "shared": true
+ }
+}
+ `)
+
+ w.Header().Add("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+
+ fmt.Fprintf(w, `
+{
+ "network": {
+ "status": "ACTIVE",
+ "subnets": [],
+ "name": "new_network_name",
+ "admin_state_up": false,
+ "tenant_id": "4fd44f30292945e481c7b8a0c8908869",
+ "shared": true,
+ "id": "4e8e5957-649f-477b-9e5b-f1f75b21c03c"
+ }
+}
+ `)
+ })
+
+ iTrue := true
+ options := os.UpdateOpts{Name: "new_network_name", AdminStateUp: os.Down, Shared: &iTrue}
+ n, err := Update(fake.ServiceClient(), "4e8e5957-649f-477b-9e5b-f1f75b21c03c", options).Extract()
+ th.AssertNoErr(t, err)
+
+ th.AssertEquals(t, n.Name, "new_network_name")
+ th.AssertEquals(t, n.AdminStateUp, false)
+ th.AssertEquals(t, n.Shared, true)
+ th.AssertEquals(t, n.ID, "4e8e5957-649f-477b-9e5b-f1f75b21c03c")
+}
+
+func TestDelete(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ th.Mux.HandleFunc("/networks/4e8e5957-649f-477b-9e5b-f1f75b21c03c", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "DELETE")
+ th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
+ w.WriteHeader(http.StatusNoContent)
+ })
+
+ res := Delete(fake.ServiceClient(), "4e8e5957-649f-477b-9e5b-f1f75b21c03c")
+ th.AssertNoErr(t, res.Err)
+}
diff --git a/rackspace/networking/v2/ports/delegate_test.go b/rackspace/networking/v2/ports/delegate_test.go
new file mode 100644
index 0000000..f53ff59
--- /dev/null
+++ b/rackspace/networking/v2/ports/delegate_test.go
@@ -0,0 +1,322 @@
+package ports
+
+import (
+ "fmt"
+ "net/http"
+ "testing"
+
+ os "github.com/rackspace/gophercloud/openstack/networking/v2/ports"
+ "github.com/rackspace/gophercloud/pagination"
+ fake "github.com/rackspace/gophercloud/rackspace/networking/v2/common"
+ th "github.com/rackspace/gophercloud/testhelper"
+)
+
+func TestList(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ th.Mux.HandleFunc("/ports", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "GET")
+ th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
+
+ w.Header().Add("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+
+ fmt.Fprintf(w, `
+{
+ "ports": [
+ {
+ "status": "ACTIVE",
+ "binding:host_id": "devstack",
+ "name": "",
+ "admin_state_up": true,
+ "network_id": "70c1db1f-b701-45bd-96e0-a313ee3430b3",
+ "tenant_id": "",
+ "device_owner": "network:router_gateway",
+ "mac_address": "fa:16:3e:58:42:ed",
+ "fixed_ips": [
+ {
+ "subnet_id": "008ba151-0b8c-4a67-98b5-0d2b87666062",
+ "ip_address": "172.24.4.2"
+ }
+ ],
+ "id": "d80b1a3b-4fc1-49f3-952e-1e2ab7081d8b",
+ "security_groups": [],
+ "device_id": "9ae135f4-b6e0-4dad-9e91-3c223e385824"
+ }
+ ]
+}
+ `)
+ })
+
+ count := 0
+
+ List(fake.ServiceClient(), os.ListOpts{}).EachPage(func(page pagination.Page) (bool, error) {
+ count++
+ actual, err := os.ExtractPorts(page)
+ if err != nil {
+ t.Errorf("Failed to extract subnets: %v", err)
+ return false, nil
+ }
+
+ expected := []os.Port{
+ os.Port{
+ Status: "ACTIVE",
+ Name: "",
+ AdminStateUp: true,
+ NetworkID: "70c1db1f-b701-45bd-96e0-a313ee3430b3",
+ TenantID: "",
+ DeviceOwner: "network:router_gateway",
+ MACAddress: "fa:16:3e:58:42:ed",
+ FixedIPs: []os.IP{
+ os.IP{
+ SubnetID: "008ba151-0b8c-4a67-98b5-0d2b87666062",
+ IPAddress: "172.24.4.2",
+ },
+ },
+ ID: "d80b1a3b-4fc1-49f3-952e-1e2ab7081d8b",
+ SecurityGroups: []string{},
+ DeviceID: "9ae135f4-b6e0-4dad-9e91-3c223e385824",
+ },
+ }
+
+ th.CheckDeepEquals(t, expected, actual)
+
+ return true, nil
+ })
+
+ if count != 1 {
+ t.Errorf("Expected 1 page, got %d", count)
+ }
+}
+
+func TestGet(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ th.Mux.HandleFunc("/ports/46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "GET")
+ th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
+
+ w.Header().Add("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+
+ fmt.Fprintf(w, `
+{
+ "port": {
+ "status": "ACTIVE",
+ "name": "",
+ "admin_state_up": true,
+ "network_id": "a87cc70a-3e15-4acf-8205-9b711a3531b7",
+ "tenant_id": "7e02058126cc4950b75f9970368ba177",
+ "device_owner": "network:router_interface",
+ "mac_address": "fa:16:3e:23:fd:d7",
+ "fixed_ips": [
+ {
+ "subnet_id": "a0304c3a-4f08-4c43-88af-d796509c97d2",
+ "ip_address": "10.0.0.1"
+ }
+ ],
+ "id": "46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2",
+ "security_groups": [],
+ "device_id": "5e3898d7-11be-483e-9732-b2f5eccd2b2e"
+ }
+}
+ `)
+ })
+
+ n, err := Get(fake.ServiceClient(), "46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2").Extract()
+ th.AssertNoErr(t, err)
+
+ th.AssertEquals(t, n.Status, "ACTIVE")
+ th.AssertEquals(t, n.Name, "")
+ th.AssertEquals(t, n.AdminStateUp, true)
+ th.AssertEquals(t, n.NetworkID, "a87cc70a-3e15-4acf-8205-9b711a3531b7")
+ th.AssertEquals(t, n.TenantID, "7e02058126cc4950b75f9970368ba177")
+ th.AssertEquals(t, n.DeviceOwner, "network:router_interface")
+ th.AssertEquals(t, n.MACAddress, "fa:16:3e:23:fd:d7")
+ th.AssertDeepEquals(t, n.FixedIPs, []os.IP{
+ os.IP{SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.1"},
+ })
+ th.AssertEquals(t, n.ID, "46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2")
+ th.AssertDeepEquals(t, n.SecurityGroups, []string{})
+ th.AssertEquals(t, n.Status, "ACTIVE")
+ th.AssertEquals(t, n.DeviceID, "5e3898d7-11be-483e-9732-b2f5eccd2b2e")
+}
+
+func TestCreate(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ th.Mux.HandleFunc("/ports", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "POST")
+ th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
+ th.TestHeader(t, r, "Content-Type", "application/json")
+ th.TestHeader(t, r, "Accept", "application/json")
+ th.TestJSONRequest(t, r, `
+{
+ "port": {
+ "network_id": "a87cc70a-3e15-4acf-8205-9b711a3531b7",
+ "name": "private-port",
+ "admin_state_up": true,
+ "fixed_ips": [
+ {
+ "subnet_id": "a0304c3a-4f08-4c43-88af-d796509c97d2",
+ "ip_address": "10.0.0.2"
+ }
+ ],
+ "security_groups": ["foo"]
+ }
+}
+ `)
+
+ w.Header().Add("Content-Type", "application/json")
+ w.WriteHeader(http.StatusCreated)
+
+ fmt.Fprintf(w, `
+{
+ "port": {
+ "status": "DOWN",
+ "name": "private-port",
+ "allowed_address_pairs": [],
+ "admin_state_up": true,
+ "network_id": "a87cc70a-3e15-4acf-8205-9b711a3531b7",
+ "tenant_id": "d6700c0c9ffa4f1cb322cd4a1f3906fa",
+ "device_owner": "",
+ "mac_address": "fa:16:3e:c9:cb:f0",
+ "fixed_ips": [
+ {
+ "subnet_id": "a0304c3a-4f08-4c43-88af-d796509c97d2",
+ "ip_address": "10.0.0.2"
+ }
+ ],
+ "id": "65c0ee9f-d634-4522-8954-51021b570b0d",
+ "security_groups": [
+ "f0ac4394-7e4a-4409-9701-ba8be283dbc3"
+ ],
+ "device_id": ""
+ }
+}
+ `)
+ })
+
+ asu := true
+ options := os.CreateOpts{
+ Name: "private-port",
+ AdminStateUp: &asu,
+ NetworkID: "a87cc70a-3e15-4acf-8205-9b711a3531b7",
+ FixedIPs: []os.IP{
+ os.IP{SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.2"},
+ },
+ SecurityGroups: []string{"foo"},
+ }
+ n, err := Create(fake.ServiceClient(), options).Extract()
+ th.AssertNoErr(t, err)
+
+ th.AssertEquals(t, n.Status, "DOWN")
+ th.AssertEquals(t, n.Name, "private-port")
+ th.AssertEquals(t, n.AdminStateUp, true)
+ th.AssertEquals(t, n.NetworkID, "a87cc70a-3e15-4acf-8205-9b711a3531b7")
+ th.AssertEquals(t, n.TenantID, "d6700c0c9ffa4f1cb322cd4a1f3906fa")
+ th.AssertEquals(t, n.DeviceOwner, "")
+ th.AssertEquals(t, n.MACAddress, "fa:16:3e:c9:cb:f0")
+ th.AssertDeepEquals(t, n.FixedIPs, []os.IP{
+ os.IP{SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.2"},
+ })
+ th.AssertEquals(t, n.ID, "65c0ee9f-d634-4522-8954-51021b570b0d")
+ th.AssertDeepEquals(t, n.SecurityGroups, []string{"f0ac4394-7e4a-4409-9701-ba8be283dbc3"})
+}
+
+func TestRequiredCreateOpts(t *testing.T) {
+ res := Create(fake.ServiceClient(), os.CreateOpts{})
+ if res.Err == nil {
+ t.Fatalf("Expected error, got none")
+ }
+}
+
+func TestUpdate(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ th.Mux.HandleFunc("/ports/65c0ee9f-d634-4522-8954-51021b570b0d", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "PUT")
+ th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
+ th.TestHeader(t, r, "Content-Type", "application/json")
+ th.TestHeader(t, r, "Accept", "application/json")
+ th.TestJSONRequest(t, r, `
+{
+ "port": {
+ "name": "new_port_name",
+ "fixed_ips": [
+ {
+ "subnet_id": "a0304c3a-4f08-4c43-88af-d796509c97d2",
+ "ip_address": "10.0.0.3"
+ }
+ ],
+ "security_groups": [
+ "f0ac4394-7e4a-4409-9701-ba8be283dbc3"
+ ]
+ }
+}
+ `)
+
+ w.Header().Add("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+
+ fmt.Fprintf(w, `
+{
+ "port": {
+ "status": "DOWN",
+ "name": "new_port_name",
+ "admin_state_up": true,
+ "network_id": "a87cc70a-3e15-4acf-8205-9b711a3531b7",
+ "tenant_id": "d6700c0c9ffa4f1cb322cd4a1f3906fa",
+ "device_owner": "",
+ "mac_address": "fa:16:3e:c9:cb:f0",
+ "fixed_ips": [
+ {
+ "subnet_id": "a0304c3a-4f08-4c43-88af-d796509c97d2",
+ "ip_address": "10.0.0.3"
+ }
+ ],
+ "id": "65c0ee9f-d634-4522-8954-51021b570b0d",
+ "security_groups": [
+ "f0ac4394-7e4a-4409-9701-ba8be283dbc3"
+ ],
+ "device_id": ""
+ }
+}
+ `)
+ })
+
+ options := os.UpdateOpts{
+ Name: "new_port_name",
+ FixedIPs: []os.IP{
+ os.IP{SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.3"},
+ },
+ SecurityGroups: []string{"f0ac4394-7e4a-4409-9701-ba8be283dbc3"},
+ }
+
+ s, err := Update(fake.ServiceClient(), "65c0ee9f-d634-4522-8954-51021b570b0d", options).Extract()
+ th.AssertNoErr(t, err)
+
+ th.AssertEquals(t, s.Name, "new_port_name")
+ th.AssertDeepEquals(t, s.FixedIPs, []os.IP{
+ os.IP{SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.3"},
+ })
+ th.AssertDeepEquals(t, s.SecurityGroups, []string{"f0ac4394-7e4a-4409-9701-ba8be283dbc3"})
+}
+
+func TestDelete(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ th.Mux.HandleFunc("/ports/65c0ee9f-d634-4522-8954-51021b570b0d", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "DELETE")
+ th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
+ w.WriteHeader(http.StatusNoContent)
+ })
+
+ res := Delete(fake.ServiceClient(), "65c0ee9f-d634-4522-8954-51021b570b0d")
+ th.AssertNoErr(t, res.Err)
+}
diff --git a/rackspace/networking/v2/subnets/delegate_test.go b/rackspace/networking/v2/subnets/delegate_test.go
new file mode 100644
index 0000000..fafc6fb
--- /dev/null
+++ b/rackspace/networking/v2/subnets/delegate_test.go
@@ -0,0 +1,363 @@
+package subnets
+
+import (
+ "fmt"
+ "net/http"
+ "testing"
+
+ os "github.com/rackspace/gophercloud/openstack/networking/v2/subnets"
+ "github.com/rackspace/gophercloud/pagination"
+ fake "github.com/rackspace/gophercloud/rackspace/networking/v2/common"
+ th "github.com/rackspace/gophercloud/testhelper"
+)
+
+func TestList(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ th.Mux.HandleFunc("/subnets", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "GET")
+ th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
+
+ w.Header().Add("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+
+ fmt.Fprintf(w, `
+{
+ "subnets": [
+ {
+ "name": "private-subnet",
+ "enable_dhcp": true,
+ "network_id": "db193ab3-96e3-4cb3-8fc5-05f4296d0324",
+ "tenant_id": "26a7980765d0414dbc1fc1f88cdb7e6e",
+ "dns_nameservers": [],
+ "allocation_pools": [
+ {
+ "start": "10.0.0.2",
+ "end": "10.0.0.254"
+ }
+ ],
+ "host_routes": [],
+ "ip_version": 4,
+ "gateway_ip": "10.0.0.1",
+ "cidr": "10.0.0.0/24",
+ "id": "08eae331-0402-425a-923c-34f7cfe39c1b"
+ },
+ {
+ "name": "my_subnet",
+ "enable_dhcp": true,
+ "network_id": "d32019d3-bc6e-4319-9c1d-6722fc136a22",
+ "tenant_id": "4fd44f30292945e481c7b8a0c8908869",
+ "dns_nameservers": [],
+ "allocation_pools": [
+ {
+ "start": "192.0.0.2",
+ "end": "192.255.255.254"
+ }
+ ],
+ "host_routes": [],
+ "ip_version": 4,
+ "gateway_ip": "192.0.0.1",
+ "cidr": "192.0.0.0/8",
+ "id": "54d6f61d-db07-451c-9ab3-b9609b6b6f0b"
+ }
+ ]
+}
+ `)
+ })
+
+ count := 0
+
+ List(fake.ServiceClient(), os.ListOpts{}).EachPage(func(page pagination.Page) (bool, error) {
+ count++
+ actual, err := os.ExtractSubnets(page)
+ if err != nil {
+ t.Errorf("Failed to extract subnets: %v", err)
+ return false, nil
+ }
+
+ expected := []os.Subnet{
+ os.Subnet{
+ Name: "private-subnet",
+ EnableDHCP: true,
+ NetworkID: "db193ab3-96e3-4cb3-8fc5-05f4296d0324",
+ TenantID: "26a7980765d0414dbc1fc1f88cdb7e6e",
+ DNSNameservers: []string{},
+ AllocationPools: []os.AllocationPool{
+ os.AllocationPool{
+ Start: "10.0.0.2",
+ End: "10.0.0.254",
+ },
+ },
+ HostRoutes: []os.HostRoute{},
+ IPVersion: 4,
+ GatewayIP: "10.0.0.1",
+ CIDR: "10.0.0.0/24",
+ ID: "08eae331-0402-425a-923c-34f7cfe39c1b",
+ },
+ os.Subnet{
+ Name: "my_subnet",
+ EnableDHCP: true,
+ NetworkID: "d32019d3-bc6e-4319-9c1d-6722fc136a22",
+ TenantID: "4fd44f30292945e481c7b8a0c8908869",
+ DNSNameservers: []string{},
+ AllocationPools: []os.AllocationPool{
+ os.AllocationPool{
+ Start: "192.0.0.2",
+ End: "192.255.255.254",
+ },
+ },
+ HostRoutes: []os.HostRoute{},
+ IPVersion: 4,
+ GatewayIP: "192.0.0.1",
+ CIDR: "192.0.0.0/8",
+ ID: "54d6f61d-db07-451c-9ab3-b9609b6b6f0b",
+ },
+ }
+
+ th.CheckDeepEquals(t, expected, actual)
+
+ return true, nil
+ })
+
+ if count != 1 {
+ t.Errorf("Expected 1 page, got %d", count)
+ }
+}
+
+func TestGet(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ th.Mux.HandleFunc("/subnets/54d6f61d-db07-451c-9ab3-b9609b6b6f0b", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "GET")
+ th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
+
+ w.Header().Add("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+
+ fmt.Fprintf(w, `
+{
+ "subnet": {
+ "name": "my_subnet",
+ "enable_dhcp": true,
+ "network_id": "d32019d3-bc6e-4319-9c1d-6722fc136a22",
+ "tenant_id": "4fd44f30292945e481c7b8a0c8908869",
+ "dns_nameservers": [],
+ "allocation_pools": [
+ {
+ "start": "192.0.0.2",
+ "end": "192.255.255.254"
+ }
+ ],
+ "host_routes": [],
+ "ip_version": 4,
+ "gateway_ip": "192.0.0.1",
+ "cidr": "192.0.0.0/8",
+ "id": "54d6f61d-db07-451c-9ab3-b9609b6b6f0b"
+ }
+}
+ `)
+ })
+
+ s, err := Get(fake.ServiceClient(), "54d6f61d-db07-451c-9ab3-b9609b6b6f0b").Extract()
+ th.AssertNoErr(t, err)
+
+ th.AssertEquals(t, s.Name, "my_subnet")
+ th.AssertEquals(t, s.EnableDHCP, true)
+ th.AssertEquals(t, s.NetworkID, "d32019d3-bc6e-4319-9c1d-6722fc136a22")
+ th.AssertEquals(t, s.TenantID, "4fd44f30292945e481c7b8a0c8908869")
+ th.AssertDeepEquals(t, s.DNSNameservers, []string{})
+ th.AssertDeepEquals(t, s.AllocationPools, []os.AllocationPool{
+ os.AllocationPool{
+ Start: "192.0.0.2",
+ End: "192.255.255.254",
+ },
+ })
+ th.AssertDeepEquals(t, s.HostRoutes, []os.HostRoute{})
+ th.AssertEquals(t, s.IPVersion, 4)
+ th.AssertEquals(t, s.GatewayIP, "192.0.0.1")
+ th.AssertEquals(t, s.CIDR, "192.0.0.0/8")
+ th.AssertEquals(t, s.ID, "54d6f61d-db07-451c-9ab3-b9609b6b6f0b")
+}
+
+func TestCreate(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ th.Mux.HandleFunc("/subnets", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "POST")
+ th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
+ th.TestHeader(t, r, "Content-Type", "application/json")
+ th.TestHeader(t, r, "Accept", "application/json")
+ th.TestJSONRequest(t, r, `
+{
+ "subnet": {
+ "network_id": "d32019d3-bc6e-4319-9c1d-6722fc136a22",
+ "ip_version": 4,
+ "cidr": "192.168.199.0/24",
+ "dns_nameservers": ["foo"],
+ "allocation_pools": [
+ {
+ "start": "192.168.199.2",
+ "end": "192.168.199.254"
+ }
+ ],
+ "host_routes": [{"destination":"","nexthop": "bar"}]
+ }
+}
+ `)
+
+ w.Header().Add("Content-Type", "application/json")
+ w.WriteHeader(http.StatusCreated)
+
+ fmt.Fprintf(w, `
+{
+ "subnet": {
+ "name": "",
+ "enable_dhcp": true,
+ "network_id": "d32019d3-bc6e-4319-9c1d-6722fc136a22",
+ "tenant_id": "4fd44f30292945e481c7b8a0c8908869",
+ "dns_nameservers": [],
+ "allocation_pools": [
+ {
+ "start": "192.168.199.2",
+ "end": "192.168.199.254"
+ }
+ ],
+ "host_routes": [],
+ "ip_version": 4,
+ "gateway_ip": "192.168.199.1",
+ "cidr": "192.168.199.0/24",
+ "id": "3b80198d-4f7b-4f77-9ef5-774d54e17126"
+ }
+}
+ `)
+ })
+
+ opts := os.CreateOpts{
+ NetworkID: "d32019d3-bc6e-4319-9c1d-6722fc136a22",
+ IPVersion: 4,
+ CIDR: "192.168.199.0/24",
+ AllocationPools: []os.AllocationPool{
+ os.AllocationPool{
+ Start: "192.168.199.2",
+ End: "192.168.199.254",
+ },
+ },
+ DNSNameservers: []string{"foo"},
+ HostRoutes: []os.HostRoute{
+ os.HostRoute{NextHop: "bar"},
+ },
+ }
+ s, err := Create(fake.ServiceClient(), opts).Extract()
+ th.AssertNoErr(t, err)
+
+ th.AssertEquals(t, s.Name, "")
+ th.AssertEquals(t, s.EnableDHCP, true)
+ th.AssertEquals(t, s.NetworkID, "d32019d3-bc6e-4319-9c1d-6722fc136a22")
+ th.AssertEquals(t, s.TenantID, "4fd44f30292945e481c7b8a0c8908869")
+ th.AssertDeepEquals(t, s.DNSNameservers, []string{})
+ th.AssertDeepEquals(t, s.AllocationPools, []os.AllocationPool{
+ os.AllocationPool{
+ Start: "192.168.199.2",
+ End: "192.168.199.254",
+ },
+ })
+ th.AssertDeepEquals(t, s.HostRoutes, []os.HostRoute{})
+ th.AssertEquals(t, s.IPVersion, 4)
+ th.AssertEquals(t, s.GatewayIP, "192.168.199.1")
+ th.AssertEquals(t, s.CIDR, "192.168.199.0/24")
+ th.AssertEquals(t, s.ID, "3b80198d-4f7b-4f77-9ef5-774d54e17126")
+}
+
+func TestRequiredCreateOpts(t *testing.T) {
+ res := Create(fake.ServiceClient(), os.CreateOpts{})
+ if res.Err == nil {
+ t.Fatalf("Expected error, got none")
+ }
+
+ res = Create(fake.ServiceClient(), os.CreateOpts{NetworkID: "foo"})
+ if res.Err == nil {
+ t.Fatalf("Expected error, got none")
+ }
+
+ res = Create(fake.ServiceClient(), os.CreateOpts{NetworkID: "foo", CIDR: "bar", IPVersion: 40})
+ if res.Err == nil {
+ t.Fatalf("Expected error, got none")
+ }
+}
+
+func TestUpdate(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ th.Mux.HandleFunc("/subnets/08eae331-0402-425a-923c-34f7cfe39c1b", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "PUT")
+ th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
+ th.TestHeader(t, r, "Content-Type", "application/json")
+ th.TestHeader(t, r, "Accept", "application/json")
+ th.TestJSONRequest(t, r, `
+{
+ "subnet": {
+ "name": "my_new_subnet",
+ "dns_nameservers": ["foo"],
+ "host_routes": [{"destination":"","nexthop": "bar"}]
+ }
+}
+ `)
+
+ w.Header().Add("Content-Type", "application/json")
+ w.WriteHeader(http.StatusCreated)
+
+ fmt.Fprintf(w, `
+{
+ "subnet": {
+ "name": "my_new_subnet",
+ "enable_dhcp": true,
+ "network_id": "db193ab3-96e3-4cb3-8fc5-05f4296d0324",
+ "tenant_id": "26a7980765d0414dbc1fc1f88cdb7e6e",
+ "dns_nameservers": [],
+ "allocation_pools": [
+ {
+ "start": "10.0.0.2",
+ "end": "10.0.0.254"
+ }
+ ],
+ "host_routes": [],
+ "ip_version": 4,
+ "gateway_ip": "10.0.0.1",
+ "cidr": "10.0.0.0/24",
+ "id": "08eae331-0402-425a-923c-34f7cfe39c1b"
+ }
+}
+ `)
+ })
+
+ opts := os.UpdateOpts{
+ Name: "my_new_subnet",
+ DNSNameservers: []string{"foo"},
+ HostRoutes: []os.HostRoute{
+ os.HostRoute{NextHop: "bar"},
+ },
+ }
+ s, err := Update(fake.ServiceClient(), "08eae331-0402-425a-923c-34f7cfe39c1b", opts).Extract()
+ th.AssertNoErr(t, err)
+
+ th.AssertEquals(t, s.Name, "my_new_subnet")
+ th.AssertEquals(t, s.ID, "08eae331-0402-425a-923c-34f7cfe39c1b")
+}
+
+func TestDelete(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ th.Mux.HandleFunc("/subnets/08eae331-0402-425a-923c-34f7cfe39c1b", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "DELETE")
+ th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
+ w.WriteHeader(http.StatusNoContent)
+ })
+
+ res := Delete(fake.ServiceClient(), "08eae331-0402-425a-923c-34f7cfe39c1b")
+ th.AssertNoErr(t, res.Err)
+}