github.com/gophercloud/gophercloud@v1.14.1/openstack/networking/v2/extensions/layer3/routers/testing/requests_test.go (about)

     1  package testing
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  	"testing"
     7  	"time"
     8  
     9  	fake "github.com/gophercloud/gophercloud/openstack/networking/v2/common"
    10  	"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers"
    11  	"github.com/gophercloud/gophercloud/pagination"
    12  	th "github.com/gophercloud/gophercloud/testhelper"
    13  )
    14  
    15  func TestList(t *testing.T) {
    16  	th.SetupHTTP()
    17  	defer th.TeardownHTTP()
    18  
    19  	th.Mux.HandleFunc("/v2.0/routers", func(w http.ResponseWriter, r *http.Request) {
    20  		th.TestMethod(t, r, "GET")
    21  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
    22  
    23  		w.Header().Add("Content-Type", "application/json")
    24  		w.WriteHeader(http.StatusOK)
    25  
    26  		fmt.Fprintf(w, `
    27  {
    28      "routers": [
    29          {
    30              "status": "ACTIVE",
    31              "external_gateway_info": null,
    32              "name": "second_routers",
    33              "admin_state_up": true,
    34              "tenant_id": "6b96ff0cb17a4b859e1e575d221683d3",
    35              "distributed": false,
    36              "id": "7177abc4-5ae9-4bb7-b0d4-89e94a4abf3b"
    37          },
    38          {
    39              "status": "ACTIVE",
    40              "external_gateway_info": {
    41                  "network_id": "3c5bcddd-6af9-4e6b-9c3e-c153e521cab8"
    42              },
    43              "name": "router1",
    44              "admin_state_up": true,
    45              "tenant_id": "33a40233088643acb66ff6eb0ebea679",
    46              "distributed": false,
    47              "id": "a9254bdb-2613-4a13-ac4c-adc581fba50d"
    48          },
    49          {
    50              "status": "ACTIVE",
    51              "external_gateway_info": {
    52                  "network_id": "2b37576e-b050-4891-8b20-e1e37a93942a",
    53                  "external_fixed_ips": [
    54                      {"ip_address": "192.0.2.17", "subnet_id": "ab561bc4-1a8e-48f2-9fbd-376fcb1a1def"},
    55                      {"ip_address": "198.51.100.33", "subnet_id": "1d699529-bdfd-43f8-bcaa-bff00c547af2"}
    56                  ],
    57                  "qos_policy_id": "6601bae5-f15a-4687-8be9-ddec9a2f8a8b"
    58              },
    59              "name": "gateway",
    60              "admin_state_up": true,
    61              "tenant_id": "a3e881e0a6534880c5473d95b9442099",
    62              "distributed": false,
    63              "id": "308a035c-005d-4452-a9fe-6f8f2f0c28d8"
    64          }
    65      ]
    66  }
    67  			`)
    68  	})
    69  
    70  	count := 0
    71  
    72  	routers.List(fake.ServiceClient(), routers.ListOpts{}).EachPage(func(page pagination.Page) (bool, error) {
    73  		count++
    74  		actual, err := routers.ExtractRouters(page)
    75  		if err != nil {
    76  			t.Errorf("Failed to extract routers: %v", err)
    77  			return false, err
    78  		}
    79  
    80  		expected := []routers.Router{
    81  			{
    82  				Status:       "ACTIVE",
    83  				GatewayInfo:  routers.GatewayInfo{NetworkID: ""},
    84  				AdminStateUp: true,
    85  				Distributed:  false,
    86  				Name:         "second_routers",
    87  				ID:           "7177abc4-5ae9-4bb7-b0d4-89e94a4abf3b",
    88  				TenantID:     "6b96ff0cb17a4b859e1e575d221683d3",
    89  			},
    90  			{
    91  				Status:       "ACTIVE",
    92  				GatewayInfo:  routers.GatewayInfo{NetworkID: "3c5bcddd-6af9-4e6b-9c3e-c153e521cab8"},
    93  				AdminStateUp: true,
    94  				Distributed:  false,
    95  				Name:         "router1",
    96  				ID:           "a9254bdb-2613-4a13-ac4c-adc581fba50d",
    97  				TenantID:     "33a40233088643acb66ff6eb0ebea679",
    98  			},
    99  			{
   100  				Status: "ACTIVE",
   101  				GatewayInfo: routers.GatewayInfo{
   102  					NetworkID: "2b37576e-b050-4891-8b20-e1e37a93942a",
   103  					ExternalFixedIPs: []routers.ExternalFixedIP{
   104  						{IPAddress: "192.0.2.17", SubnetID: "ab561bc4-1a8e-48f2-9fbd-376fcb1a1def"},
   105  						{IPAddress: "198.51.100.33", SubnetID: "1d699529-bdfd-43f8-bcaa-bff00c547af2"},
   106  					},
   107  					QoSPolicyID: "6601bae5-f15a-4687-8be9-ddec9a2f8a8b",
   108  				},
   109  				AdminStateUp: true,
   110  				Distributed:  false,
   111  				Name:         "gateway",
   112  				ID:           "308a035c-005d-4452-a9fe-6f8f2f0c28d8",
   113  				TenantID:     "a3e881e0a6534880c5473d95b9442099",
   114  			},
   115  		}
   116  
   117  		th.CheckDeepEquals(t, expected, actual)
   118  
   119  		return true, nil
   120  	})
   121  
   122  	if count != 1 {
   123  		t.Errorf("Expected 1 page, got %d", count)
   124  	}
   125  }
   126  
   127  func TestCreate(t *testing.T) {
   128  	th.SetupHTTP()
   129  	defer th.TeardownHTTP()
   130  
   131  	th.Mux.HandleFunc("/v2.0/routers", func(w http.ResponseWriter, r *http.Request) {
   132  		th.TestMethod(t, r, "POST")
   133  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   134  		th.TestHeader(t, r, "Content-Type", "application/json")
   135  		th.TestHeader(t, r, "Accept", "application/json")
   136  		th.TestJSONRequest(t, r, `
   137  {
   138     "router":{
   139        "name": "foo_router",
   140        "admin_state_up": false,
   141        "external_gateway_info":{
   142           "enable_snat": false,
   143           "network_id":"8ca37218-28ff-41cb-9b10-039601ea7e6b",
   144           "external_fixed_ips": [
   145               {"subnet_id": "ab561bc4-1a8e-48f2-9fbd-376fcb1a1def"}
   146           ],
   147           "qos_policy_id": "6601bae5-f15a-4687-8be9-ddec9a2f8a8b"
   148  	  },
   149  	  "availability_zone_hints": ["zone1", "zone2"]
   150     }
   151  }
   152  			`)
   153  
   154  		w.Header().Add("Content-Type", "application/json")
   155  		w.WriteHeader(http.StatusCreated)
   156  
   157  		fmt.Fprintf(w, `
   158  {
   159      "router": {
   160          "status": "ACTIVE",
   161          "external_gateway_info": {
   162              "network_id": "8ca37218-28ff-41cb-9b10-039601ea7e6b",
   163              "enable_snat": false,
   164              "external_fixed_ips": [
   165                  {"ip_address": "192.0.2.17", "subnet_id": "ab561bc4-1a8e-48f2-9fbd-376fcb1a1def"}
   166              ],
   167              "qos_policy_id": "6601bae5-f15a-4687-8be9-ddec9a2f8a8b"
   168          },
   169          "name": "foo_router",
   170          "admin_state_up": false,
   171          "tenant_id": "6b96ff0cb17a4b859e1e575d221683d3",
   172  		"distributed": false,
   173  		"availability_zone_hints": ["zone1", "zone2"],
   174          "id": "8604a0de-7f6b-409a-a47c-a1cc7bc77b2e"
   175      }
   176  }
   177  		`)
   178  	})
   179  
   180  	asu := false
   181  	enableSNAT := false
   182  	qosID := "6601bae5-f15a-4687-8be9-ddec9a2f8a8b"
   183  	efi := []routers.ExternalFixedIP{
   184  		{
   185  			SubnetID: "ab561bc4-1a8e-48f2-9fbd-376fcb1a1def",
   186  		},
   187  	}
   188  	gwi := routers.GatewayInfo{
   189  		NetworkID:        "8ca37218-28ff-41cb-9b10-039601ea7e6b",
   190  		EnableSNAT:       &enableSNAT,
   191  		ExternalFixedIPs: efi,
   192  		QoSPolicyID:      qosID,
   193  	}
   194  	options := routers.CreateOpts{
   195  		Name:                  "foo_router",
   196  		AdminStateUp:          &asu,
   197  		GatewayInfo:           &gwi,
   198  		AvailabilityZoneHints: []string{"zone1", "zone2"},
   199  	}
   200  	r, err := routers.Create(fake.ServiceClient(), options).Extract()
   201  	th.AssertNoErr(t, err)
   202  
   203  	gwi.ExternalFixedIPs = []routers.ExternalFixedIP{{
   204  		IPAddress: "192.0.2.17",
   205  		SubnetID:  "ab561bc4-1a8e-48f2-9fbd-376fcb1a1def",
   206  	}}
   207  
   208  	th.AssertEquals(t, "foo_router", r.Name)
   209  	th.AssertEquals(t, false, r.AdminStateUp)
   210  	th.AssertDeepEquals(t, gwi, r.GatewayInfo)
   211  	th.AssertDeepEquals(t, []string{"zone1", "zone2"}, r.AvailabilityZoneHints)
   212  }
   213  
   214  func TestGet(t *testing.T) {
   215  	th.SetupHTTP()
   216  	defer th.TeardownHTTP()
   217  
   218  	th.Mux.HandleFunc("/v2.0/routers/a07eea83-7710-4860-931b-5fe220fae533", func(w http.ResponseWriter, r *http.Request) {
   219  		th.TestMethod(t, r, "GET")
   220  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   221  
   222  		w.Header().Add("Content-Type", "application/json")
   223  		w.WriteHeader(http.StatusOK)
   224  
   225  		fmt.Fprintf(w, `
   226  {
   227      "router": {
   228          "status": "ACTIVE",
   229          "external_gateway_info": {
   230              "network_id": "85d76829-6415-48ff-9c63-5c5ca8c61ac6",
   231              "external_fixed_ips": [
   232                  {"ip_address": "198.51.100.33", "subnet_id": "1d699529-bdfd-43f8-bcaa-bff00c547af2"}
   233              ],
   234              "qos_policy_id": "6601bae5-f15a-4687-8be9-ddec9a2f8a8b"
   235          },
   236          "routes": [
   237              {
   238                  "nexthop": "10.1.0.10",
   239                  "destination": "40.0.1.0/24"
   240              }
   241          ],
   242          "name": "router1",
   243          "admin_state_up": true,
   244          "tenant_id": "d6554fe62e2f41efbb6e026fad5c1542",
   245  		"distributed": false,
   246  		"availability_zone_hints": ["zone1", "zone2"],
   247          "id": "a07eea83-7710-4860-931b-5fe220fae533"
   248      }
   249  }
   250  			`)
   251  	})
   252  
   253  	n, err := routers.Get(fake.ServiceClient(), "a07eea83-7710-4860-931b-5fe220fae533").Extract()
   254  	th.AssertNoErr(t, err)
   255  
   256  	th.AssertEquals(t, n.Status, "ACTIVE")
   257  	th.AssertDeepEquals(t, n.GatewayInfo, routers.GatewayInfo{
   258  		NetworkID: "85d76829-6415-48ff-9c63-5c5ca8c61ac6",
   259  		ExternalFixedIPs: []routers.ExternalFixedIP{
   260  			{IPAddress: "198.51.100.33", SubnetID: "1d699529-bdfd-43f8-bcaa-bff00c547af2"},
   261  		},
   262  		QoSPolicyID: "6601bae5-f15a-4687-8be9-ddec9a2f8a8b",
   263  	})
   264  	th.AssertEquals(t, n.Name, "router1")
   265  	th.AssertEquals(t, n.AdminStateUp, true)
   266  	th.AssertEquals(t, n.TenantID, "d6554fe62e2f41efbb6e026fad5c1542")
   267  	th.AssertEquals(t, n.ID, "a07eea83-7710-4860-931b-5fe220fae533")
   268  	th.AssertDeepEquals(t, n.Routes, []routers.Route{{DestinationCIDR: "40.0.1.0/24", NextHop: "10.1.0.10"}})
   269  	th.AssertDeepEquals(t, n.AvailabilityZoneHints, []string{"zone1", "zone2"})
   270  }
   271  
   272  func TestUpdate(t *testing.T) {
   273  	th.SetupHTTP()
   274  	defer th.TeardownHTTP()
   275  
   276  	th.Mux.HandleFunc("/v2.0/routers/4e8e5957-649f-477b-9e5b-f1f75b21c03c", func(w http.ResponseWriter, r *http.Request) {
   277  		th.TestMethod(t, r, "PUT")
   278  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   279  		th.TestHeader(t, r, "Content-Type", "application/json")
   280  		th.TestHeader(t, r, "Accept", "application/json")
   281  		th.TestJSONRequest(t, r, `
   282  {
   283      "router": {
   284  			"name": "new_name",
   285          "external_gateway_info": {
   286              "network_id": "8ca37218-28ff-41cb-9b10-039601ea7e6b",
   287              "qos_policy_id": "01ba32e5-f15a-4687-8be9-ddec92a2f8a8"
   288  		},
   289          "routes": [
   290              {
   291                  "nexthop": "10.1.0.10",
   292                  "destination": "40.0.1.0/24"
   293              }
   294          ]
   295      }
   296  }
   297  			`)
   298  
   299  		w.Header().Add("Content-Type", "application/json")
   300  		w.WriteHeader(http.StatusOK)
   301  
   302  		fmt.Fprintf(w, `
   303  {
   304      "router": {
   305          "status": "ACTIVE",
   306          "external_gateway_info": {
   307              "network_id": "8ca37218-28ff-41cb-9b10-039601ea7e6b",
   308              "external_fixed_ips": [
   309                  {"ip_address": "192.0.2.17", "subnet_id": "ab561bc4-1a8e-48f2-9fbd-376fcb1a1def"}
   310              ],
   311              "qos_policy_id": "01ba32e5-f15a-4687-8be9-ddec92a2f8a8"
   312          },
   313          "name": "new_name",
   314          "admin_state_up": true,
   315          "tenant_id": "6b96ff0cb17a4b859e1e575d221683d3",
   316          "distributed": false,
   317          "id": "8604a0de-7f6b-409a-a47c-a1cc7bc77b2e",
   318          "routes": [
   319              {
   320                  "nexthop": "10.1.0.10",
   321                  "destination": "40.0.1.0/24"
   322              }
   323          ]
   324      }
   325  }
   326  		`)
   327  	})
   328  
   329  	gwi := routers.GatewayInfo{
   330  		NetworkID:   "8ca37218-28ff-41cb-9b10-039601ea7e6b",
   331  		QoSPolicyID: "01ba32e5-f15a-4687-8be9-ddec92a2f8a8",
   332  	}
   333  	r := []routers.Route{{DestinationCIDR: "40.0.1.0/24", NextHop: "10.1.0.10"}}
   334  	options := routers.UpdateOpts{Name: "new_name", GatewayInfo: &gwi, Routes: &r}
   335  
   336  	n, err := routers.Update(fake.ServiceClient(), "4e8e5957-649f-477b-9e5b-f1f75b21c03c", options).Extract()
   337  	th.AssertNoErr(t, err)
   338  
   339  	gwi.ExternalFixedIPs = []routers.ExternalFixedIP{
   340  		{IPAddress: "192.0.2.17", SubnetID: "ab561bc4-1a8e-48f2-9fbd-376fcb1a1def"},
   341  	}
   342  
   343  	th.AssertEquals(t, n.Name, "new_name")
   344  	th.AssertDeepEquals(t, n.GatewayInfo, gwi)
   345  	th.AssertDeepEquals(t, n.Routes, []routers.Route{{DestinationCIDR: "40.0.1.0/24", NextHop: "10.1.0.10"}})
   346  }
   347  
   348  func TestUpdateWithoutRoutes(t *testing.T) {
   349  	th.SetupHTTP()
   350  	defer th.TeardownHTTP()
   351  
   352  	th.Mux.HandleFunc("/v2.0/routers/4e8e5957-649f-477b-9e5b-f1f75b21c03c", func(w http.ResponseWriter, r *http.Request) {
   353  		th.TestMethod(t, r, "PUT")
   354  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   355  		th.TestHeader(t, r, "Content-Type", "application/json")
   356  		th.TestHeader(t, r, "Accept", "application/json")
   357  		th.TestJSONRequest(t, r, `
   358  {
   359      "router": {
   360          "name": "new_name"
   361      }
   362  }
   363  		`)
   364  
   365  		w.Header().Add("Content-Type", "application/json")
   366  		w.WriteHeader(http.StatusOK)
   367  
   368  		fmt.Fprintf(w, `
   369  {
   370      "router": {
   371          "status": "ACTIVE",
   372          "external_gateway_info": {
   373              "network_id": "8ca37218-28ff-41cb-9b10-039601ea7e6b",
   374              "external_fixed_ips": [
   375                  {"ip_address": "192.0.2.17", "subnet_id": "ab561bc4-1a8e-48f2-9fbd-376fcb1a1def"}
   376              ]
   377          },
   378          "name": "new_name",
   379          "admin_state_up": true,
   380          "tenant_id": "6b96ff0cb17a4b859e1e575d221683d3",
   381          "distributed": false,
   382          "id": "8604a0de-7f6b-409a-a47c-a1cc7bc77b2e",
   383          "routes": [
   384              {
   385                  "nexthop": "10.1.0.10",
   386                  "destination": "40.0.1.0/24"
   387              }
   388          ]
   389      }
   390  }
   391  		`)
   392  	})
   393  
   394  	options := routers.UpdateOpts{Name: "new_name"}
   395  
   396  	n, err := routers.Update(fake.ServiceClient(), "4e8e5957-649f-477b-9e5b-f1f75b21c03c", options).Extract()
   397  	th.AssertNoErr(t, err)
   398  
   399  	th.AssertEquals(t, n.Name, "new_name")
   400  	th.AssertDeepEquals(t, n.Routes, []routers.Route{{DestinationCIDR: "40.0.1.0/24", NextHop: "10.1.0.10"}})
   401  }
   402  
   403  func TestAllRoutesRemoved(t *testing.T) {
   404  	th.SetupHTTP()
   405  	defer th.TeardownHTTP()
   406  
   407  	th.Mux.HandleFunc("/v2.0/routers/4e8e5957-649f-477b-9e5b-f1f75b21c03c", func(w http.ResponseWriter, r *http.Request) {
   408  		th.TestMethod(t, r, "PUT")
   409  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   410  		th.TestHeader(t, r, "Content-Type", "application/json")
   411  		th.TestHeader(t, r, "Accept", "application/json")
   412  		th.TestJSONRequest(t, r, `
   413  {
   414      "router": {
   415          "routes": []
   416      }
   417  }
   418  			`)
   419  
   420  		w.Header().Add("Content-Type", "application/json")
   421  		w.WriteHeader(http.StatusOK)
   422  
   423  		fmt.Fprintf(w, `
   424  {
   425      "router": {
   426          "status": "ACTIVE",
   427          "external_gateway_info": {
   428              "network_id": "8ca37218-28ff-41cb-9b10-039601ea7e6b"
   429          },
   430          "name": "name",
   431          "admin_state_up": true,
   432          "tenant_id": "6b96ff0cb17a4b859e1e575d221683d3",
   433          "distributed": false,
   434          "id": "8604a0de-7f6b-409a-a47c-a1cc7bc77b2e",
   435          "routes": []
   436      }
   437  }
   438  		`)
   439  	})
   440  
   441  	r := []routers.Route{}
   442  	options := routers.UpdateOpts{Routes: &r}
   443  
   444  	n, err := routers.Update(fake.ServiceClient(), "4e8e5957-649f-477b-9e5b-f1f75b21c03c", options).Extract()
   445  	th.AssertNoErr(t, err)
   446  
   447  	th.AssertDeepEquals(t, n.Routes, []routers.Route{})
   448  }
   449  
   450  func TestDelete(t *testing.T) {
   451  	th.SetupHTTP()
   452  	defer th.TeardownHTTP()
   453  
   454  	th.Mux.HandleFunc("/v2.0/routers/4e8e5957-649f-477b-9e5b-f1f75b21c03c", func(w http.ResponseWriter, r *http.Request) {
   455  		th.TestMethod(t, r, "DELETE")
   456  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   457  		w.WriteHeader(http.StatusNoContent)
   458  	})
   459  
   460  	res := routers.Delete(fake.ServiceClient(), "4e8e5957-649f-477b-9e5b-f1f75b21c03c")
   461  	th.AssertNoErr(t, res.Err)
   462  }
   463  
   464  func TestAddInterface(t *testing.T) {
   465  	th.SetupHTTP()
   466  	defer th.TeardownHTTP()
   467  
   468  	th.Mux.HandleFunc("/v2.0/routers/4e8e5957-649f-477b-9e5b-f1f75b21c03c/add_router_interface", func(w http.ResponseWriter, r *http.Request) {
   469  		th.TestMethod(t, r, "PUT")
   470  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   471  		th.TestHeader(t, r, "Content-Type", "application/json")
   472  		th.TestHeader(t, r, "Accept", "application/json")
   473  		th.TestJSONRequest(t, r, `
   474  {
   475      "subnet_id": "a2f1f29d-571b-4533-907f-5803ab96ead1"
   476  }
   477  	`)
   478  
   479  		w.Header().Add("Content-Type", "application/json")
   480  		w.WriteHeader(http.StatusOK)
   481  
   482  		fmt.Fprintf(w, `
   483  {
   484      "subnet_id": "0d32a837-8069-4ec3-84c4-3eef3e10b188",
   485      "tenant_id": "017d8de156df4177889f31a9bd6edc00",
   486      "port_id": "3f990102-4485-4df1-97a0-2c35bdb85b31",
   487      "id": "9a83fa11-8da5-436e-9afe-3d3ac5ce7770"
   488  }
   489  `)
   490  	})
   491  
   492  	opts := routers.AddInterfaceOpts{SubnetID: "a2f1f29d-571b-4533-907f-5803ab96ead1"}
   493  	res, err := routers.AddInterface(fake.ServiceClient(), "4e8e5957-649f-477b-9e5b-f1f75b21c03c", opts).Extract()
   494  	th.AssertNoErr(t, err)
   495  
   496  	th.AssertEquals(t, "0d32a837-8069-4ec3-84c4-3eef3e10b188", res.SubnetID)
   497  	th.AssertEquals(t, "017d8de156df4177889f31a9bd6edc00", res.TenantID)
   498  	th.AssertEquals(t, "3f990102-4485-4df1-97a0-2c35bdb85b31", res.PortID)
   499  	th.AssertEquals(t, "9a83fa11-8da5-436e-9afe-3d3ac5ce7770", res.ID)
   500  }
   501  
   502  func TestAddInterfaceRequiredOpts(t *testing.T) {
   503  	_, err := routers.AddInterface(fake.ServiceClient(), "foo", routers.AddInterfaceOpts{}).Extract()
   504  	if err == nil {
   505  		t.Fatalf("Expected error, got none")
   506  	}
   507  	_, err = routers.AddInterface(fake.ServiceClient(), "foo", routers.AddInterfaceOpts{SubnetID: "bar", PortID: "baz"}).Extract()
   508  	if err == nil {
   509  		t.Fatalf("Expected error, got none")
   510  	}
   511  }
   512  
   513  func TestRemoveInterface(t *testing.T) {
   514  	th.SetupHTTP()
   515  	defer th.TeardownHTTP()
   516  
   517  	th.Mux.HandleFunc("/v2.0/routers/4e8e5957-649f-477b-9e5b-f1f75b21c03c/remove_router_interface", func(w http.ResponseWriter, r *http.Request) {
   518  		th.TestMethod(t, r, "PUT")
   519  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   520  		th.TestHeader(t, r, "Content-Type", "application/json")
   521  		th.TestHeader(t, r, "Accept", "application/json")
   522  		th.TestJSONRequest(t, r, `
   523  {
   524  		"subnet_id": "a2f1f29d-571b-4533-907f-5803ab96ead1"
   525  }
   526  	`)
   527  
   528  		w.Header().Add("Content-Type", "application/json")
   529  		w.WriteHeader(http.StatusOK)
   530  
   531  		fmt.Fprintf(w, `
   532  {
   533  		"subnet_id": "0d32a837-8069-4ec3-84c4-3eef3e10b188",
   534  		"tenant_id": "017d8de156df4177889f31a9bd6edc00",
   535  		"port_id": "3f990102-4485-4df1-97a0-2c35bdb85b31",
   536  		"id": "9a83fa11-8da5-436e-9afe-3d3ac5ce7770"
   537  }
   538  `)
   539  	})
   540  
   541  	opts := routers.RemoveInterfaceOpts{SubnetID: "a2f1f29d-571b-4533-907f-5803ab96ead1"}
   542  	res, err := routers.RemoveInterface(fake.ServiceClient(), "4e8e5957-649f-477b-9e5b-f1f75b21c03c", opts).Extract()
   543  	th.AssertNoErr(t, err)
   544  
   545  	th.AssertEquals(t, "0d32a837-8069-4ec3-84c4-3eef3e10b188", res.SubnetID)
   546  	th.AssertEquals(t, "017d8de156df4177889f31a9bd6edc00", res.TenantID)
   547  	th.AssertEquals(t, "3f990102-4485-4df1-97a0-2c35bdb85b31", res.PortID)
   548  	th.AssertEquals(t, "9a83fa11-8da5-436e-9afe-3d3ac5ce7770", res.ID)
   549  }
   550  
   551  func TestListL3Agents(t *testing.T) {
   552  	th.SetupHTTP()
   553  	defer th.TeardownHTTP()
   554  
   555  	th.Mux.HandleFunc("/v2.0/routers/fa3a4aaa-c73f-48aa-a603-8c8bf642b7c0/l3-agents", func(w http.ResponseWriter, r *http.Request) {
   556  		th.TestMethod(t, r, "GET")
   557  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   558  
   559  		w.Header().Add("Content-Type", "application/json")
   560  		w.WriteHeader(http.StatusOK)
   561  
   562  		fmt.Fprintf(w, `
   563  {
   564      "agents": [
   565          {
   566              "id": "ddbf087c-e38f-4a73-bcb3-c38f2a719a03",
   567              "agent_type": "L3 agent",
   568              "binary": "neutron-l3-agent",
   569              "topic": "l3_agent",
   570              "host": "os-ctrl-02",
   571              "admin_state_up": true,
   572              "created_at": "2017-07-26 23:15:44",
   573              "started_at": "2018-06-26 21:46:19",
   574              "heartbeat_timestamp": "2019-01-09 10:28:53",
   575              "description": "My L3 agent for OpenStack",
   576              "resources_synced": true,
   577              "availability_zone": "nova",
   578              "alive": true,
   579              "configurations": {
   580                  "agent_mode": "legacy",
   581                  "ex_gw_ports": 2,
   582                  "floating_ips": 2,
   583                  "handle_internal_only_routers": true,
   584                  "interface_driver": "linuxbridge",
   585                  "interfaces": 1,
   586                  "log_agent_heartbeats": false,
   587                  "routers": 2
   588              },
   589              "resource_versions": {},
   590              "ha_state": "standby"
   591          },
   592          {
   593              "id": "4541cc6c-87bc-4cee-bad2-36ca78836c91",
   594              "agent_type": "L3 agent",
   595              "binary": "neutron-l3-agent",
   596              "topic": "l3_agent",
   597              "host": "os-ctrl-03",
   598              "admin_state_up": true,
   599              "created_at": "2017-01-22 14:00:50",
   600              "started_at": "2018-11-06 12:09:17",
   601              "heartbeat_timestamp": "2019-01-09 10:28:50",
   602              "description": "My L3 agent for OpenStack",
   603              "resources_synced": true,
   604              "availability_zone": "nova",
   605              "alive": true,
   606              "configurations": {
   607                  "agent_mode": "legacy",
   608                  "ex_gw_ports": 2,
   609                  "floating_ips": 2,
   610                  "handle_internal_only_routers": true,
   611                  "interface_driver": "linuxbridge",
   612                  "interfaces": 1,
   613                  "log_agent_heartbeats": false,
   614                  "routers": 2
   615              },
   616              "resource_versions": {},
   617              "ha_state": "active"
   618          }
   619      ]
   620  }
   621  			`)
   622  	})
   623  
   624  	l3AgentsPages, err := routers.ListL3Agents(fake.ServiceClient(), "fa3a4aaa-c73f-48aa-a603-8c8bf642b7c0").AllPages()
   625  	th.AssertNoErr(t, err)
   626  	actual, err := routers.ExtractL3Agents(l3AgentsPages)
   627  	th.AssertNoErr(t, err)
   628  
   629  	expected := []routers.L3Agent{
   630  		{
   631  			ID:               "ddbf087c-e38f-4a73-bcb3-c38f2a719a03",
   632  			AdminStateUp:     true,
   633  			AgentType:        "L3 agent",
   634  			Description:      "My L3 agent for OpenStack",
   635  			Alive:            true,
   636  			ResourcesSynced:  true,
   637  			Binary:           "neutron-l3-agent",
   638  			AvailabilityZone: "nova",
   639  			Configurations: map[string]interface{}{
   640  				"agent_mode":                   "legacy",
   641  				"ex_gw_ports":                  float64(2),
   642  				"floating_ips":                 float64(2),
   643  				"handle_internal_only_routers": true,
   644  				"interface_driver":             "linuxbridge",
   645  				"interfaces":                   float64(1),
   646  				"log_agent_heartbeats":         false,
   647  				"routers":                      float64(2),
   648  			},
   649  			CreatedAt:          time.Date(2017, 7, 26, 23, 15, 44, 0, time.UTC),
   650  			StartedAt:          time.Date(2018, 6, 26, 21, 46, 19, 0, time.UTC),
   651  			HeartbeatTimestamp: time.Date(2019, 1, 9, 10, 28, 53, 0, time.UTC),
   652  			Host:               "os-ctrl-02",
   653  			Topic:              "l3_agent",
   654  			HAState:            "standby",
   655  			ResourceVersions:   map[string]interface{}{},
   656  		},
   657  		{
   658  			ID:               "4541cc6c-87bc-4cee-bad2-36ca78836c91",
   659  			AdminStateUp:     true,
   660  			AgentType:        "L3 agent",
   661  			Description:      "My L3 agent for OpenStack",
   662  			Alive:            true,
   663  			ResourcesSynced:  true,
   664  			Binary:           "neutron-l3-agent",
   665  			AvailabilityZone: "nova",
   666  			Configurations: map[string]interface{}{
   667  				"agent_mode":                   "legacy",
   668  				"ex_gw_ports":                  float64(2),
   669  				"floating_ips":                 float64(2),
   670  				"handle_internal_only_routers": true,
   671  				"interface_driver":             "linuxbridge",
   672  				"interfaces":                   float64(1),
   673  				"log_agent_heartbeats":         false,
   674  				"routers":                      float64(2),
   675  			},
   676  			CreatedAt:          time.Date(2017, 1, 22, 14, 00, 50, 0, time.UTC),
   677  			StartedAt:          time.Date(2018, 11, 6, 12, 9, 17, 0, time.UTC),
   678  			HeartbeatTimestamp: time.Date(2019, 1, 9, 10, 28, 50, 0, time.UTC),
   679  			Host:               "os-ctrl-03",
   680  			Topic:              "l3_agent",
   681  			HAState:            "active",
   682  			ResourceVersions:   map[string]interface{}{},
   683  		},
   684  	}
   685  	th.CheckDeepEquals(t, expected, actual)
   686  }