Feature/filestorage sharenetworks list (#124)

* sfs: Add list for share networks

* sfs: Add acceptance tests for share network List

* sfs: Add more fields for filtering List requests

* sfs: Add pagination for share network List

* sfs: Change pagination to use MarkerPage

* sfs: Add acceptance tests for share network pagination
diff --git a/openstack/sharedfilesystems/v2/sharenetworks/testing/fixtures.go b/openstack/sharedfilesystems/v2/sharenetworks/testing/fixtures.go
index a014e5e..a99bb9a 100644
--- a/openstack/sharedfilesystems/v2/sharenetworks/testing/fixtures.go
+++ b/openstack/sharedfilesystems/v2/sharenetworks/testing/fixtures.go
@@ -11,34 +11,34 @@
 
 func createReq(name, description, network, subnetwork string) string {
 	return fmt.Sprintf(`{
-		"share_network": {
-			"name": "%s",
-			"description": "%s",
-			"neutron_net_id": "%s",
-			"neutron_subnet_id": "%s"
-		}
-	}`, name, description, network, subnetwork)
+        "share_network": {
+            "name": "%s",
+            "description": "%s",
+            "neutron_net_id": "%s",
+            "neutron_subnet_id": "%s"
+        }
+    }`, name, description, network, subnetwork)
 }
 
 func createResp(name, description, network, subnetwork string) string {
 	return fmt.Sprintf(`
-	{
-		"share_network": {
-			"name": "%s",
-			"description": "%s",
-			"segmentation_id": null,
-			"created_at": "2015-09-07T14:37:00.583656",
-			"updated_at": null,
-			"id": "77eb3421-4549-4789-ac39-0d5185d68c29",
-			"neutron_net_id": "%s",
-			"neutron_subnet_id": "%s",
-			"ip_version": null,
-			"nova_net_id": null,
-			"cidr": null,
-			"project_id": "e10a683c20da41248cfd5e1ab3d88c62",
-			"network_type": null
-		}
-	}`, name, description, network, subnetwork)
+    {
+        "share_network": {
+            "name": "%s",
+            "description": "%s",
+            "segmentation_id": null,
+            "created_at": "2015-09-07T14:37:00.583656",
+            "updated_at": null,
+            "id": "77eb3421-4549-4789-ac39-0d5185d68c29",
+            "neutron_net_id": "%s",
+            "neutron_subnet_id": "%s",
+            "ip_version": null,
+            "nova_net_id": null,
+            "cidr": null,
+            "project_id": "e10a683c20da41248cfd5e1ab3d88c62",
+            "network_type": null
+        }
+    }`, name, description, network, subnetwork)
 }
 
 func MockCreateResponse(t *testing.T) {
@@ -69,3 +69,157 @@
 		w.WriteHeader(http.StatusAccepted)
 	})
 }
+
+func MockListResponse(t *testing.T) {
+	th.Mux.HandleFunc("/share-networks/detail", 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)
+
+		r.ParseForm()
+		marker := r.Form.Get("offset")
+
+		switch marker {
+		case "":
+			fmt.Fprintf(w, `{
+            "share_networks": [
+                {
+                    "name": "net_my1",
+                    "segmentation_id": null,
+                    "created_at": "2015-09-04T14:57:13.000000",
+                    "neutron_subnet_id": "53482b62-2c84-4a53-b6ab-30d9d9800d06",
+                    "updated_at": null,
+                    "id": "32763294-e3d4-456a-998d-60047677c2fb",
+                    "neutron_net_id": "998b42ee-2cee-4d36-8b95-67b5ca1f2109",
+                    "ip_version": null,
+                    "nova_net_id": null,
+                    "cidr": null,
+                    "project_id": "16e1ab15c35a457e9c2b2aa189f544e1",
+                    "network_type": null,
+                    "description": "descr"
+                },
+                {
+                    "name": "net_my",
+                    "segmentation_id": null,
+                    "created_at": "2015-09-04T14:54:25.000000",
+                    "neutron_subnet_id": "53482b62-2c84-4a53-b6ab-30d9d9800d06",
+                    "updated_at": null,
+                    "id": "713df749-aac0-4a54-af52-10f6c991e80c",
+                    "neutron_net_id": "998b42ee-2cee-4d36-8b95-67b5ca1f2109",
+                    "ip_version": null,
+                    "nova_net_id": null,
+                    "cidr": null,
+                    "project_id": "16e1ab15c35a457e9c2b2aa189f544e1",
+                    "network_type": null,
+                    "description": "desecr"
+                },
+                {
+                    "name": null,
+                    "segmentation_id": null,
+                    "created_at": "2015-09-04T14:51:41.000000",
+                    "neutron_subnet_id": null,
+                    "updated_at": null,
+                    "id": "fa158a3d-6d9f-4187-9ca5-abbb82646eb2",
+                    "neutron_net_id": null,
+                    "ip_version": null,
+                    "nova_net_id": null,
+                    "cidr": null,
+                    "project_id": "16e1ab15c35a457e9c2b2aa189f544e1",
+                    "network_type": null,
+                    "description": null
+                }
+            ]
+        }`)
+		default:
+			fmt.Fprintf(w, `
+				{
+					"share_networks": []
+				}`)
+		}
+	})
+}
+
+func MockFilteredListResponse(t *testing.T) {
+	th.Mux.HandleFunc("/share-networks/detail", 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)
+
+		r.ParseForm()
+		marker := r.Form.Get("offset")
+		switch marker {
+		case "":
+			fmt.Fprintf(w, `
+				{
+					"share_networks": [
+						{
+							"name": "net_my1",
+							"segmentation_id": null,
+							"created_at": "2015-09-04T14:57:13.000000",
+							"neutron_subnet_id": "53482b62-2c84-4a53-b6ab-30d9d9800d06",
+							"updated_at": null,
+							"id": "32763294-e3d4-456a-998d-60047677c2fb",
+							"neutron_net_id": "998b42ee-2cee-4d36-8b95-67b5ca1f2109",
+							"ip_version": null,
+							"nova_net_id": null,
+							"cidr": null,
+							"project_id": "16e1ab15c35a457e9c2b2aa189f544e1",
+							"network_type": null,
+							"description": "descr"
+						}
+					]
+				}`)
+		case "1":
+			fmt.Fprintf(w, `
+				{
+					"share_networks": [
+						{
+							"name": "net_my1",
+							"segmentation_id": null,
+							"created_at": "2015-09-04T14:57:13.000000",
+							"neutron_subnet_id": "53482b62-2c84-4a53-b6ab-30d9d9800d06",
+							"updated_at": null,
+							"id": "32763294-e3d4-456a-998d-60047677c2fb",
+							"neutron_net_id": "998b42ee-2cee-4d36-8b95-67b5ca1f2109",
+							"ip_version": null,
+							"nova_net_id": null,
+							"cidr": null,
+							"project_id": "16e1ab15c35a457e9c2b2aa189f544e1",
+							"network_type": null,
+							"description": "descr"
+						}
+					]
+				}`)
+		case "2":
+			fmt.Fprintf(w, `
+				{
+					"share_networks": [
+						{
+							"name": "net_my1",
+							"segmentation_id": null,
+							"created_at": "2015-09-04T14:57:13.000000",
+							"neutron_subnet_id": "53482b62-2c84-4a53-b6ab-30d9d9800d06",
+							"updated_at": null,
+							"id": "32763294-e3d4-456a-998d-60047677c2fb",
+							"neutron_net_id": "998b42ee-2cee-4d36-8b95-67b5ca1f2109",
+							"ip_version": null,
+							"nova_net_id": null,
+							"cidr": null,
+							"project_id": "16e1ab15c35a457e9c2b2aa189f544e1",
+							"network_type": null,
+							"description": "descr"
+						}
+					]
+				}`)
+		default:
+			fmt.Fprintf(w, `
+				{
+					"share_networks": []
+				}`)
+		}
+	})
+}
diff --git a/openstack/sharedfilesystems/v2/sharenetworks/testing/requests_test.go b/openstack/sharedfilesystems/v2/sharenetworks/testing/requests_test.go
index 15baf0d..f13f1da 100644
--- a/openstack/sharedfilesystems/v2/sharenetworks/testing/requests_test.go
+++ b/openstack/sharedfilesystems/v2/sharenetworks/testing/requests_test.go
@@ -2,8 +2,11 @@
 
 import (
 	"testing"
+	"time"
 
+	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/openstack/sharedfilesystems/v2/sharenetworks"
+	"github.com/gophercloud/gophercloud/pagination"
 	th "github.com/gophercloud/gophercloud/testhelper"
 	"github.com/gophercloud/gophercloud/testhelper/client"
 )
@@ -41,3 +44,97 @@
 	res := sharenetworks.Delete(client.ServiceClient(), "fa158a3d-6d9f-4187-9ca5-abbb82646eb2")
 	th.AssertNoErr(t, res.Err)
 }
+
+// Verifies that share networks can be listed correctly
+func TestListDetail(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+
+	MockListResponse(t)
+
+	allPages, err := sharenetworks.ListDetail(client.ServiceClient(), &sharenetworks.ListOpts{}).AllPages()
+
+	th.AssertNoErr(t, err)
+	actual, err := sharenetworks.ExtractShareNetworks(allPages)
+	th.AssertNoErr(t, err)
+
+	var nilTime time.Time
+	expected := []sharenetworks.ShareNetwork{
+		{
+			ID:              "32763294-e3d4-456a-998d-60047677c2fb",
+			Name:            "net_my1",
+			CreatedAt:       gophercloud.JSONRFC3339MilliNoZ(time.Date(2015, 9, 4, 14, 57, 13, 0, time.UTC)),
+			Description:     "descr",
+			NetworkType:     "",
+			CIDR:            "",
+			NovaNetID:       "",
+			NeutronNetID:    "998b42ee-2cee-4d36-8b95-67b5ca1f2109",
+			NeutronSubnetID: "53482b62-2c84-4a53-b6ab-30d9d9800d06",
+			IPVersion:       0,
+			SegmentationID:  0,
+			UpdatedAt:       gophercloud.JSONRFC3339MilliNoZ(nilTime),
+			ProjectID:       "16e1ab15c35a457e9c2b2aa189f544e1",
+		},
+		{
+			ID:              "713df749-aac0-4a54-af52-10f6c991e80c",
+			Name:            "net_my",
+			CreatedAt:       gophercloud.JSONRFC3339MilliNoZ(time.Date(2015, 9, 4, 14, 54, 25, 0, time.UTC)),
+			Description:     "desecr",
+			NetworkType:     "",
+			CIDR:            "",
+			NovaNetID:       "",
+			NeutronNetID:    "998b42ee-2cee-4d36-8b95-67b5ca1f2109",
+			NeutronSubnetID: "53482b62-2c84-4a53-b6ab-30d9d9800d06",
+			IPVersion:       0,
+			SegmentationID:  0,
+			UpdatedAt:       gophercloud.JSONRFC3339MilliNoZ(nilTime),
+			ProjectID:       "16e1ab15c35a457e9c2b2aa189f544e1",
+		},
+		{
+			ID:              "fa158a3d-6d9f-4187-9ca5-abbb82646eb2",
+			Name:            "",
+			CreatedAt:       gophercloud.JSONRFC3339MilliNoZ(time.Date(2015, 9, 4, 14, 51, 41, 0, time.UTC)),
+			Description:     "",
+			NetworkType:     "",
+			CIDR:            "",
+			NovaNetID:       "",
+			NeutronNetID:    "",
+			NeutronSubnetID: "",
+			IPVersion:       0,
+			SegmentationID:  0,
+			UpdatedAt:       gophercloud.JSONRFC3339MilliNoZ(nilTime),
+			ProjectID:       "16e1ab15c35a457e9c2b2aa189f544e1",
+		},
+	}
+
+	th.CheckDeepEquals(t, expected, actual)
+}
+
+// Verifies that share networks list can be called with query parameters
+func TestPaginatedListDetail(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+
+	MockFilteredListResponse(t)
+
+	options := &sharenetworks.ListOpts{
+		Offset: 0,
+		Limit:  1,
+	}
+
+	count := 0
+
+	err := sharenetworks.ListDetail(client.ServiceClient(), options).EachPage(func(page pagination.Page) (bool, error) {
+		count++
+		_, err := sharenetworks.ExtractShareNetworks(page)
+		if err != nil {
+			t.Errorf("Failed to extract share networks: %v", err)
+			return false, err
+		}
+
+		return true, nil
+	})
+	th.AssertNoErr(t, err)
+
+	th.AssertEquals(t, count, 3)
+}