Finished floating IP acceptance tests
diff --git a/acceptance/openstack/networking/v2/extensions/layer3_test.go b/acceptance/openstack/networking/v2/extensions/layer3_test.go
index 59ae2e5..1b97197 100644
--- a/acceptance/openstack/networking/v2/extensions/layer3_test.go
+++ b/acceptance/openstack/networking/v2/extensions/layer3_test.go
@@ -7,8 +7,10 @@
 
 	base "github.com/rackspace/gophercloud/acceptance/openstack/networking/v2"
 	"github.com/rackspace/gophercloud/openstack/networking/v2/extensions/external"
+	"github.com/rackspace/gophercloud/openstack/networking/v2/extensions/layer3/floatingips"
 	"github.com/rackspace/gophercloud/openstack/networking/v2/extensions/layer3/routers"
 	"github.com/rackspace/gophercloud/openstack/networking/v2/networks"
+	"github.com/rackspace/gophercloud/openstack/networking/v2/ports"
 	"github.com/rackspace/gophercloud/openstack/networking/v2/subnets"
 	"github.com/rackspace/gophercloud/pagination"
 	th "github.com/rackspace/gophercloud/testhelper"
@@ -19,10 +21,15 @@
 	cidr2 = "20.0.0.1/24"
 )
 
-func TestRouterCRUD(t *testing.T) {
+func TestAll(t *testing.T) {
 	base.Setup(t)
 	defer base.Teardown()
 
+	//testRouter(t)
+	testFloatingIP(t)
+}
+
+func testRouter(t *testing.T) {
 	// Setup: Create network
 	networkID := createNetwork(t)
 
@@ -51,7 +58,43 @@
 	deleteRouter(t, routerID)
 
 	// Cleanup
-	networks.Delete(base.Client, networkID)
+	deleteNetwork(t, networkID)
+}
+
+func testFloatingIP(t *testing.T) {
+	// Setup external network
+	extNetworkID := createNetwork(t)
+
+	// Setup internal network, subnet and port
+	intNetworkID, subnetID, portID := createInternalTopology(t)
+
+	// Now the important part: we need to allow the external network to talk to
+	// the internal subnet. For this we need a router that has an interface to
+	// the internal subnet.
+	routerID := bridgeIntSubnetWithExtNetwork(t, extNetworkID, subnetID)
+
+	// Create floating IP
+	ipID := createFloatingIP(t, extNetworkID, portID)
+
+	// Get floating IP
+	getFloatingIP(t, ipID)
+
+	// Update floating IP
+	updateFloatingIP(t, ipID, portID)
+
+	// Delete floating IP
+	deleteFloatingIP(t, ipID)
+
+	// Remove the internal subnet interface
+	removeInterface(t, routerID, subnetID)
+
+	// Delete router and external network
+	deleteRouter(t, routerID)
+	deleteNetwork(t, extNetworkID)
+
+	// Delete internal port and network
+	deletePort(t, portID)
+	deleteNetwork(t, intNetworkID)
 }
 
 func createNetwork(t *testing.T) string {
@@ -77,14 +120,55 @@
 	return n.ID
 }
 
+func deleteNetwork(t *testing.T, networkID string) {
+	t.Logf("Deleting network %s", networkID)
+	networks.Delete(base.Client, networkID)
+}
+
+func deletePort(t *testing.T, portID string) {
+	t.Logf("Deleting port %s", portID)
+	ports.Delete(base.Client, portID)
+}
+
+func createInternalTopology(t *testing.T) (string, string, string) {
+	t.Logf("Creating an internal network (for port)")
+	opts := networks.CreateOpts{Name: "internal_network"}
+	n, err := networks.Create(base.Client, opts).Extract()
+	th.AssertNoErr(t, err)
+
+	// A subnet is also needed
+	subnetID := createSubnet(t, n.ID, cidr2)
+
+	t.Logf("Creating an internal port on network %s", n.ID)
+	p, err := ports.Create(base.Client, ports.CreateOpts{
+		NetworkID: n.ID,
+		Name:      "fixed_internal_port",
+	}).Extract()
+	th.AssertNoErr(t, err)
+
+	return n.ID, subnetID, p.ID
+}
+
+func bridgeIntSubnetWithExtNetwork(t *testing.T, networkID, subnetID string) string {
+	// Create router with external gateway info
+	routerID := createRouter(t, networkID)
+
+	// Add interface for internal subnet
+	addInterface(t, routerID, subnetID)
+
+	return routerID
+}
+
 func createSubnet(t *testing.T, networkID, cidr string) string {
 	t.Logf("Creating a subnet for network %s", networkID)
 
+	iFalse := false
 	s, err := subnets.Create(base.Client, subnets.CreateOpts{
-		NetworkID: networkID,
-		CIDR:      cidr,
-		IPVersion: subnets.IPv4,
-		Name:      "my_subnet",
+		NetworkID:  networkID,
+		CIDR:       cidr,
+		IPVersion:  subnets.IPv4,
+		Name:       "my_subnet",
+		EnableDHCP: &iFalse,
 	}).Extract()
 
 	th.AssertNoErr(t, err)
@@ -158,7 +242,7 @@
 
 	th.AssertNoErr(t, err)
 
-	t.Logf("Interface added to router %s: ID [%s] SubnetID [%s] PortID [%s]", routerID, ir.ID, ir.SubnetID, ir.PortID)
+	t.Logf("Interface added to router %s: SubnetID [%s] PortID [%s]", routerID, ir.SubnetID, ir.PortID)
 }
 
 func removeInterface(t *testing.T, routerID, subnetID string) {
@@ -176,3 +260,44 @@
 
 	th.AssertNoErr(t, res.Err)
 }
+
+func createFloatingIP(t *testing.T, networkID, portID string) string {
+	t.Logf("Creating floating IP on network [%s] with port [%s]", networkID, portID)
+
+	opts := floatingips.CreateOpts{
+		FloatingNetworkID: networkID,
+		PortID:            portID,
+	}
+
+	ip, err := floatingips.Create(base.Client, opts).Extract()
+
+	th.AssertNoErr(t, err)
+
+	t.Logf("Floating IP created: ID [%s] Status [%s] Fixed (internal) IP: [%s] Floating (external) IP: [%s]",
+		ip.ID, ip.Status, ip.FixedIP, ip.FloatingIP)
+
+	return ip.ID
+}
+
+func getFloatingIP(t *testing.T, ipID string) {
+	ip, err := floatingips.Get(base.Client, ipID).Extract()
+	th.AssertNoErr(t, err)
+
+	t.Logf("Getting floating IP: ID [%s] Status [%s]", ip.ID, ip.Status)
+}
+
+func updateFloatingIP(t *testing.T, ipID, portID string) {
+	t.Logf("Disassociate all ports from IP %s", ipID)
+	_, err := floatingips.Update(base.Client, ipID, floatingips.UpdateOpts{PortID: ""}).Extract()
+	th.AssertNoErr(t, err)
+
+	t.Logf("Re-associate the port %s", portID)
+	_, err = floatingips.Update(base.Client, ipID, floatingips.UpdateOpts{PortID: portID}).Extract()
+	th.AssertNoErr(t, err)
+}
+
+func deleteFloatingIP(t *testing.T, ipID string) {
+	t.Logf("Deleting IP %s", ipID)
+	res := floatingips.Delete(base.Client, ipID)
+	th.AssertNoErr(t, res.Err)
+}