move unit tests into 'testing' directories
diff --git a/openstack/compute/v2/servers/testing/doc.go b/openstack/compute/v2/servers/testing/doc.go
new file mode 100644
index 0000000..7603f83
--- /dev/null
+++ b/openstack/compute/v2/servers/testing/doc.go
@@ -0,0 +1 @@
+package testing
diff --git a/openstack/compute/v2/servers/testing/fixtures.go b/openstack/compute/v2/servers/testing/fixtures.go
new file mode 100644
index 0000000..b4fb7ff
--- /dev/null
+++ b/openstack/compute/v2/servers/testing/fixtures.go
@@ -0,0 +1,722 @@
+package testing
+
+import (
+	"fmt"
+	"net/http"
+	"testing"
+
+	"github.com/gophercloud/gophercloud"
+	"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
+	th "github.com/gophercloud/gophercloud/testhelper"
+	"github.com/gophercloud/gophercloud/testhelper/client"
+)
+
+// ServerListBody contains the canned body of a servers.List response.
+const ServerListBody = `
+{
+	"servers": [
+		{
+			"status": "ACTIVE",
+			"updated": "2014-09-25T13:10:10Z",
+			"hostId": "29d3c8c896a45aa4c34e52247875d7fefc3d94bbcc9f622b5d204362",
+			"OS-EXT-SRV-ATTR:host": "devstack",
+			"addresses": {
+				"private": [
+					{
+						"OS-EXT-IPS-MAC:mac_addr": "fa:16:3e:7c:1b:2b",
+						"version": 4,
+						"addr": "10.0.0.32",
+						"OS-EXT-IPS:type": "fixed"
+					}
+				]
+			},
+			"links": [
+				{
+					"href": "http://104.130.131.164:8774/v2/fcad67a6189847c4aecfa3c81a05783b/servers/ef079b0c-e610-4dfb-b1aa-b49f07ac48e5",
+					"rel": "self"
+				},
+				{
+					"href": "http://104.130.131.164:8774/fcad67a6189847c4aecfa3c81a05783b/servers/ef079b0c-e610-4dfb-b1aa-b49f07ac48e5",
+					"rel": "bookmark"
+				}
+			],
+			"key_name": null,
+			"image": {
+				"id": "f90f6034-2570-4974-8351-6b49732ef2eb",
+				"links": [
+					{
+						"href": "http://104.130.131.164:8774/fcad67a6189847c4aecfa3c81a05783b/images/f90f6034-2570-4974-8351-6b49732ef2eb",
+						"rel": "bookmark"
+					}
+				]
+			},
+			"OS-EXT-STS:task_state": null,
+			"OS-EXT-STS:vm_state": "active",
+			"OS-EXT-SRV-ATTR:instance_name": "instance-0000001e",
+			"OS-SRV-USG:launched_at": "2014-09-25T13:10:10.000000",
+			"OS-EXT-SRV-ATTR:hypervisor_hostname": "devstack",
+			"flavor": {
+				"id": "1",
+				"links": [
+					{
+						"href": "http://104.130.131.164:8774/fcad67a6189847c4aecfa3c81a05783b/flavors/1",
+						"rel": "bookmark"
+					}
+				]
+			},
+			"id": "ef079b0c-e610-4dfb-b1aa-b49f07ac48e5",
+			"security_groups": [
+				{
+					"name": "default"
+				}
+			],
+			"OS-SRV-USG:terminated_at": null,
+			"OS-EXT-AZ:availability_zone": "nova",
+			"user_id": "9349aff8be7545ac9d2f1d00999a23cd",
+			"name": "herp",
+			"created": "2014-09-25T13:10:02Z",
+			"tenant_id": "fcad67a6189847c4aecfa3c81a05783b",
+			"OS-DCF:diskConfig": "MANUAL",
+			"os-extended-volumes:volumes_attached": [],
+			"accessIPv4": "",
+			"accessIPv6": "",
+			"progress": 0,
+			"OS-EXT-STS:power_state": 1,
+			"config_drive": "",
+			"metadata": {}
+		},
+		{
+			"status": "ACTIVE",
+			"updated": "2014-09-25T13:04:49Z",
+			"hostId": "29d3c8c896a45aa4c34e52247875d7fefc3d94bbcc9f622b5d204362",
+			"OS-EXT-SRV-ATTR:host": "devstack",
+			"addresses": {
+				"private": [
+					{
+						"OS-EXT-IPS-MAC:mac_addr": "fa:16:3e:9e:89:be",
+						"version": 4,
+						"addr": "10.0.0.31",
+						"OS-EXT-IPS:type": "fixed"
+					}
+				]
+			},
+			"links": [
+				{
+					"href": "http://104.130.131.164:8774/v2/fcad67a6189847c4aecfa3c81a05783b/servers/9e5476bd-a4ec-4653-93d6-72c93aa682ba",
+					"rel": "self"
+				},
+				{
+					"href": "http://104.130.131.164:8774/fcad67a6189847c4aecfa3c81a05783b/servers/9e5476bd-a4ec-4653-93d6-72c93aa682ba",
+					"rel": "bookmark"
+				}
+			],
+			"key_name": null,
+			"image": {
+				"id": "f90f6034-2570-4974-8351-6b49732ef2eb",
+				"links": [
+					{
+						"href": "http://104.130.131.164:8774/fcad67a6189847c4aecfa3c81a05783b/images/f90f6034-2570-4974-8351-6b49732ef2eb",
+						"rel": "bookmark"
+					}
+				]
+			},
+			"OS-EXT-STS:task_state": null,
+			"OS-EXT-STS:vm_state": "active",
+			"OS-EXT-SRV-ATTR:instance_name": "instance-0000001d",
+			"OS-SRV-USG:launched_at": "2014-09-25T13:04:49.000000",
+			"OS-EXT-SRV-ATTR:hypervisor_hostname": "devstack",
+			"flavor": {
+				"id": "1",
+				"links": [
+					{
+						"href": "http://104.130.131.164:8774/fcad67a6189847c4aecfa3c81a05783b/flavors/1",
+						"rel": "bookmark"
+					}
+				]
+			},
+			"id": "9e5476bd-a4ec-4653-93d6-72c93aa682ba",
+			"security_groups": [
+				{
+					"name": "default"
+				}
+			],
+			"OS-SRV-USG:terminated_at": null,
+			"OS-EXT-AZ:availability_zone": "nova",
+			"user_id": "9349aff8be7545ac9d2f1d00999a23cd",
+			"name": "derp",
+			"created": "2014-09-25T13:04:41Z",
+			"tenant_id": "fcad67a6189847c4aecfa3c81a05783b",
+			"OS-DCF:diskConfig": "MANUAL",
+			"os-extended-volumes:volumes_attached": [],
+			"accessIPv4": "",
+			"accessIPv6": "",
+			"progress": 0,
+			"OS-EXT-STS:power_state": 1,
+			"config_drive": "",
+			"metadata": {}
+		}
+	]
+}
+`
+
+// SingleServerBody is the canned body of a Get request on an existing server.
+const SingleServerBody = `
+{
+	"server": {
+		"status": "ACTIVE",
+		"updated": "2014-09-25T13:04:49Z",
+		"hostId": "29d3c8c896a45aa4c34e52247875d7fefc3d94bbcc9f622b5d204362",
+		"OS-EXT-SRV-ATTR:host": "devstack",
+		"addresses": {
+			"private": [
+				{
+					"OS-EXT-IPS-MAC:mac_addr": "fa:16:3e:9e:89:be",
+					"version": 4,
+					"addr": "10.0.0.31",
+					"OS-EXT-IPS:type": "fixed"
+				}
+			]
+		},
+		"links": [
+			{
+				"href": "http://104.130.131.164:8774/v2/fcad67a6189847c4aecfa3c81a05783b/servers/9e5476bd-a4ec-4653-93d6-72c93aa682ba",
+				"rel": "self"
+			},
+			{
+				"href": "http://104.130.131.164:8774/fcad67a6189847c4aecfa3c81a05783b/servers/9e5476bd-a4ec-4653-93d6-72c93aa682ba",
+				"rel": "bookmark"
+			}
+		],
+		"key_name": null,
+		"image": {
+			"id": "f90f6034-2570-4974-8351-6b49732ef2eb",
+			"links": [
+				{
+					"href": "http://104.130.131.164:8774/fcad67a6189847c4aecfa3c81a05783b/images/f90f6034-2570-4974-8351-6b49732ef2eb",
+					"rel": "bookmark"
+				}
+			]
+		},
+		"OS-EXT-STS:task_state": null,
+		"OS-EXT-STS:vm_state": "active",
+		"OS-EXT-SRV-ATTR:instance_name": "instance-0000001d",
+		"OS-SRV-USG:launched_at": "2014-09-25T13:04:49.000000",
+		"OS-EXT-SRV-ATTR:hypervisor_hostname": "devstack",
+		"flavor": {
+			"id": "1",
+			"links": [
+				{
+					"href": "http://104.130.131.164:8774/fcad67a6189847c4aecfa3c81a05783b/flavors/1",
+					"rel": "bookmark"
+				}
+			]
+		},
+		"id": "9e5476bd-a4ec-4653-93d6-72c93aa682ba",
+		"security_groups": [
+			{
+				"name": "default"
+			}
+		],
+		"OS-SRV-USG:terminated_at": null,
+		"OS-EXT-AZ:availability_zone": "nova",
+		"user_id": "9349aff8be7545ac9d2f1d00999a23cd",
+		"name": "derp",
+		"created": "2014-09-25T13:04:41Z",
+		"tenant_id": "fcad67a6189847c4aecfa3c81a05783b",
+		"OS-DCF:diskConfig": "MANUAL",
+		"os-extended-volumes:volumes_attached": [],
+		"accessIPv4": "",
+		"accessIPv6": "",
+		"progress": 0,
+		"OS-EXT-STS:power_state": 1,
+		"config_drive": "",
+		"metadata": {}
+	}
+}
+`
+
+const ServerPasswordBody = `
+{
+    "password": "xlozO3wLCBRWAa2yDjCCVx8vwNPypxnypmRYDa/zErlQ+EzPe1S/Gz6nfmC52mOlOSCRuUOmG7kqqgejPof6M7bOezS387zjq4LSvvwp28zUknzy4YzfFGhnHAdai3TxUJ26pfQCYrq8UTzmKF2Bq8ioSEtVVzM0A96pDh8W2i7BOz6MdoiVyiev/I1K2LsuipfxSJR7Wdke4zNXJjHHP2RfYsVbZ/k9ANu+Nz4iIH8/7Cacud/pphH7EjrY6a4RZNrjQskrhKYed0YERpotyjYk1eDtRe72GrSiXteqCM4biaQ5w3ruS+AcX//PXk3uJ5kC7d67fPXaVz4WaQRYMg=="
+}
+`
+
+var (
+	// ServerHerp is a Server struct that should correspond to the first result in ServerListBody.
+	ServerHerp = servers.Server{
+		Status:  "ACTIVE",
+		Updated: "2014-09-25T13:10:10Z",
+		HostID:  "29d3c8c896a45aa4c34e52247875d7fefc3d94bbcc9f622b5d204362",
+		Addresses: map[string]interface{}{
+			"private": []interface{}{
+				map[string]interface{}{
+					"OS-EXT-IPS-MAC:mac_addr": "fa:16:3e:7c:1b:2b",
+					"version":                 float64(4),
+					"addr":                    "10.0.0.32",
+					"OS-EXT-IPS:type":         "fixed",
+				},
+			},
+		},
+		Links: []interface{}{
+			map[string]interface{}{
+				"href": "http://104.130.131.164:8774/v2/fcad67a6189847c4aecfa3c81a05783b/servers/ef079b0c-e610-4dfb-b1aa-b49f07ac48e5",
+				"rel":  "self",
+			},
+			map[string]interface{}{
+				"href": "http://104.130.131.164:8774/fcad67a6189847c4aecfa3c81a05783b/servers/ef079b0c-e610-4dfb-b1aa-b49f07ac48e5",
+				"rel":  "bookmark",
+			},
+		},
+		Image: map[string]interface{}{
+			"id": "f90f6034-2570-4974-8351-6b49732ef2eb",
+			"links": []interface{}{
+				map[string]interface{}{
+					"href": "http://104.130.131.164:8774/fcad67a6189847c4aecfa3c81a05783b/images/f90f6034-2570-4974-8351-6b49732ef2eb",
+					"rel":  "bookmark",
+				},
+			},
+		},
+		Flavor: map[string]interface{}{
+			"id": "1",
+			"links": []interface{}{
+				map[string]interface{}{
+					"href": "http://104.130.131.164:8774/fcad67a6189847c4aecfa3c81a05783b/flavors/1",
+					"rel":  "bookmark",
+				},
+			},
+		},
+		ID:       "ef079b0c-e610-4dfb-b1aa-b49f07ac48e5",
+		UserID:   "9349aff8be7545ac9d2f1d00999a23cd",
+		Name:     "herp",
+		Created:  "2014-09-25T13:10:02Z",
+		TenantID: "fcad67a6189847c4aecfa3c81a05783b",
+		Metadata: map[string]interface{}{},
+		SecurityGroups: []map[string]interface{}{
+			map[string]interface{}{
+				"name": "default",
+			},
+		},
+	}
+
+	// ServerDerp is a Server struct that should correspond to the second server in ServerListBody.
+	ServerDerp = servers.Server{
+		Status:  "ACTIVE",
+		Updated: "2014-09-25T13:04:49Z",
+		HostID:  "29d3c8c896a45aa4c34e52247875d7fefc3d94bbcc9f622b5d204362",
+		Addresses: map[string]interface{}{
+			"private": []interface{}{
+				map[string]interface{}{
+					"OS-EXT-IPS-MAC:mac_addr": "fa:16:3e:9e:89:be",
+					"version":                 float64(4),
+					"addr":                    "10.0.0.31",
+					"OS-EXT-IPS:type":         "fixed",
+				},
+			},
+		},
+		Links: []interface{}{
+			map[string]interface{}{
+				"href": "http://104.130.131.164:8774/v2/fcad67a6189847c4aecfa3c81a05783b/servers/9e5476bd-a4ec-4653-93d6-72c93aa682ba",
+				"rel":  "self",
+			},
+			map[string]interface{}{
+				"href": "http://104.130.131.164:8774/fcad67a6189847c4aecfa3c81a05783b/servers/9e5476bd-a4ec-4653-93d6-72c93aa682ba",
+				"rel":  "bookmark",
+			},
+		},
+		Image: map[string]interface{}{
+			"id": "f90f6034-2570-4974-8351-6b49732ef2eb",
+			"links": []interface{}{
+				map[string]interface{}{
+					"href": "http://104.130.131.164:8774/fcad67a6189847c4aecfa3c81a05783b/images/f90f6034-2570-4974-8351-6b49732ef2eb",
+					"rel":  "bookmark",
+				},
+			},
+		},
+		Flavor: map[string]interface{}{
+			"id": "1",
+			"links": []interface{}{
+				map[string]interface{}{
+					"href": "http://104.130.131.164:8774/fcad67a6189847c4aecfa3c81a05783b/flavors/1",
+					"rel":  "bookmark",
+				},
+			},
+		},
+		ID:       "9e5476bd-a4ec-4653-93d6-72c93aa682ba",
+		UserID:   "9349aff8be7545ac9d2f1d00999a23cd",
+		Name:     "derp",
+		Created:  "2014-09-25T13:04:41Z",
+		TenantID: "fcad67a6189847c4aecfa3c81a05783b",
+		Metadata: map[string]interface{}{},
+		SecurityGroups: []map[string]interface{}{
+			map[string]interface{}{
+				"name": "default",
+			},
+		},
+	}
+)
+
+type CreateOptsWithCustomField struct {
+	servers.CreateOpts
+	Foo string `json:"foo,omitempty"`
+}
+
+func (opts CreateOptsWithCustomField) ToServerCreateMap() (map[string]interface{}, error) {
+	return gophercloud.BuildRequestBody(opts, "server")
+}
+
+// HandleServerCreationSuccessfully sets up the test server to respond to a server creation request
+// with a given response.
+func HandleServerCreationSuccessfully(t *testing.T, response string) {
+	th.Mux.HandleFunc("/servers", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "POST")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+		th.TestJSONRequest(t, r, `{
+			"server": {
+				"name": "derp",
+				"imageRef": "f90f6034-2570-4974-8351-6b49732ef2eb",
+				"flavorRef": "1"
+			}
+		}`)
+
+		w.WriteHeader(http.StatusAccepted)
+		w.Header().Add("Content-Type", "application/json")
+		fmt.Fprintf(w, response)
+	})
+}
+
+// HandleServerCreationWithCustomFieldSuccessfully sets up the test server to respond to a server creation request
+// with a given response.
+func HandleServerCreationWithCustomFieldSuccessfully(t *testing.T, response string) {
+	th.Mux.HandleFunc("/servers", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "POST")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+		th.TestJSONRequest(t, r, `{
+			"server": {
+				"name": "derp",
+				"imageRef": "f90f6034-2570-4974-8351-6b49732ef2eb",
+				"flavorRef": "1",
+				"foo": "bar"
+			}
+		}`)
+
+		w.WriteHeader(http.StatusAccepted)
+		w.Header().Add("Content-Type", "application/json")
+		fmt.Fprintf(w, response)
+	})
+}
+
+// HandleServerListSuccessfully sets up the test server to respond to a server List request.
+func HandleServerListSuccessfully(t *testing.T) {
+	th.Mux.HandleFunc("/servers/detail", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "GET")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+
+		w.Header().Add("Content-Type", "application/json")
+		r.ParseForm()
+		marker := r.Form.Get("marker")
+		switch marker {
+		case "":
+			fmt.Fprintf(w, ServerListBody)
+		case "9e5476bd-a4ec-4653-93d6-72c93aa682ba":
+			fmt.Fprintf(w, `{ "servers": [] }`)
+		default:
+			t.Fatalf("/servers/detail invoked with unexpected marker=[%s]", marker)
+		}
+	})
+}
+
+// HandleServerDeletionSuccessfully sets up the test server to respond to a server deletion request.
+func HandleServerDeletionSuccessfully(t *testing.T) {
+	th.Mux.HandleFunc("/servers/asdfasdfasdf", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "DELETE")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+
+		w.WriteHeader(http.StatusNoContent)
+	})
+}
+
+// HandleServerForceDeletionSuccessfully sets up the test server to respond to a server force deletion
+// request.
+func HandleServerForceDeletionSuccessfully(t *testing.T) {
+	th.Mux.HandleFunc("/servers/asdfasdfasdf/action", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "POST")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+		th.TestJSONRequest(t, r, `{ "forceDelete": "" }`)
+
+		w.WriteHeader(http.StatusAccepted)
+	})
+}
+
+// HandleServerGetSuccessfully sets up the test server to respond to a server Get request.
+func HandleServerGetSuccessfully(t *testing.T) {
+	th.Mux.HandleFunc("/servers/1234asdf", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "GET")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+		th.TestHeader(t, r, "Accept", "application/json")
+
+		fmt.Fprintf(w, SingleServerBody)
+	})
+}
+
+// HandleServerUpdateSuccessfully sets up the test server to respond to a server Update request.
+func HandleServerUpdateSuccessfully(t *testing.T) {
+	th.Mux.HandleFunc("/servers/1234asdf", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "PUT")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+		th.TestHeader(t, r, "Accept", "application/json")
+		th.TestHeader(t, r, "Content-Type", "application/json")
+		th.TestJSONRequest(t, r, `{ "server": { "name": "new-name" } }`)
+
+		fmt.Fprintf(w, SingleServerBody)
+	})
+}
+
+// HandleAdminPasswordChangeSuccessfully sets up the test server to respond to a server password
+// change request.
+func HandleAdminPasswordChangeSuccessfully(t *testing.T) {
+	th.Mux.HandleFunc("/servers/1234asdf/action", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "POST")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+		th.TestJSONRequest(t, r, `{ "changePassword": { "adminPass": "new-password" } }`)
+
+		w.WriteHeader(http.StatusAccepted)
+	})
+}
+
+// HandleRebootSuccessfully sets up the test server to respond to a reboot request with success.
+func HandleRebootSuccessfully(t *testing.T) {
+	th.Mux.HandleFunc("/servers/1234asdf/action", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "POST")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+		th.TestJSONRequest(t, r, `{ "reboot": { "type": "SOFT" } }`)
+
+		w.WriteHeader(http.StatusAccepted)
+	})
+}
+
+// HandleRebuildSuccessfully sets up the test server to respond to a rebuild request with success.
+func HandleRebuildSuccessfully(t *testing.T, response string) {
+	th.Mux.HandleFunc("/servers/1234asdf/action", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "POST")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+		th.TestJSONRequest(t, r, `
+			{
+				"rebuild": {
+					"name": "new-name",
+					"adminPass": "swordfish",
+					"imageRef": "http://104.130.131.164:8774/fcad67a6189847c4aecfa3c81a05783b/images/f90f6034-2570-4974-8351-6b49732ef2eb",
+					"accessIPv4": "1.2.3.4"
+				}
+			}
+		`)
+
+		w.WriteHeader(http.StatusAccepted)
+		w.Header().Add("Content-Type", "application/json")
+		fmt.Fprintf(w, response)
+	})
+}
+
+// HandleServerRescueSuccessfully sets up the test server to respond to a server Rescue request.
+func HandleServerRescueSuccessfully(t *testing.T) {
+	th.Mux.HandleFunc("/servers/1234asdf/action", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "POST")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+		th.TestJSONRequest(t, r, `{ "rescue": { "adminPass": "1234567890" } }`)
+
+		w.WriteHeader(http.StatusOK)
+		w.Write([]byte(`{ "adminPass": "1234567890" }`))
+	})
+}
+
+// HandleMetadatumGetSuccessfully sets up the test server to respond to a metadatum Get request.
+func HandleMetadatumGetSuccessfully(t *testing.T) {
+	th.Mux.HandleFunc("/servers/1234asdf/metadata/foo", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "GET")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+		th.TestHeader(t, r, "Accept", "application/json")
+
+		w.WriteHeader(http.StatusOK)
+		w.Header().Add("Content-Type", "application/json")
+		w.Write([]byte(`{ "meta": {"foo":"bar"}}`))
+	})
+}
+
+// HandleMetadatumCreateSuccessfully sets up the test server to respond to a metadatum Create request.
+func HandleMetadatumCreateSuccessfully(t *testing.T) {
+	th.Mux.HandleFunc("/servers/1234asdf/metadata/foo", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "PUT")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+		th.TestJSONRequest(t, r, `{
+			"meta": {
+				"foo": "bar"
+			}
+		}`)
+
+		w.WriteHeader(http.StatusOK)
+		w.Header().Add("Content-Type", "application/json")
+		w.Write([]byte(`{ "meta": {"foo":"bar"}}`))
+	})
+}
+
+// HandleMetadatumDeleteSuccessfully sets up the test server to respond to a metadatum Delete request.
+func HandleMetadatumDeleteSuccessfully(t *testing.T) {
+	th.Mux.HandleFunc("/servers/1234asdf/metadata/foo", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "DELETE")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+
+		w.WriteHeader(http.StatusNoContent)
+	})
+}
+
+// HandleMetadataGetSuccessfully sets up the test server to respond to a metadata Get request.
+func HandleMetadataGetSuccessfully(t *testing.T) {
+	th.Mux.HandleFunc("/servers/1234asdf/metadata", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "GET")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+		th.TestHeader(t, r, "Accept", "application/json")
+
+		w.WriteHeader(http.StatusOK)
+		w.Write([]byte(`{ "metadata": {"foo":"bar", "this":"that"}}`))
+	})
+}
+
+// HandleMetadataResetSuccessfully sets up the test server to respond to a metadata Create request.
+func HandleMetadataResetSuccessfully(t *testing.T) {
+	th.Mux.HandleFunc("/servers/1234asdf/metadata", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "PUT")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+		th.TestJSONRequest(t, r, `{
+				"metadata": {
+					"foo": "bar",
+					"this": "that"
+				}
+			}`)
+
+		w.WriteHeader(http.StatusOK)
+		w.Header().Add("Content-Type", "application/json")
+		w.Write([]byte(`{ "metadata": {"foo":"bar", "this":"that"}}`))
+	})
+}
+
+// HandleMetadataUpdateSuccessfully sets up the test server to respond to a metadata Update request.
+func HandleMetadataUpdateSuccessfully(t *testing.T) {
+	th.Mux.HandleFunc("/servers/1234asdf/metadata", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "POST")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+		th.TestJSONRequest(t, r, `{
+				"metadata": {
+					"foo": "baz",
+					"this": "those"
+				}
+			}`)
+
+		w.WriteHeader(http.StatusOK)
+		w.Header().Add("Content-Type", "application/json")
+		w.Write([]byte(`{ "metadata": {"foo":"baz", "this":"those"}}`))
+	})
+}
+
+// ListAddressesExpected represents an expected repsonse from a ListAddresses request.
+var ListAddressesExpected = map[string][]servers.Address{
+	"public": []servers.Address{
+		{
+			Version: 4,
+			Address: "80.56.136.39",
+		},
+		{
+			Version: 6,
+			Address: "2001:4800:790e:510:be76:4eff:fe04:82a8",
+		},
+	},
+	"private": []servers.Address{
+		{
+			Version: 4,
+			Address: "10.880.3.154",
+		},
+	},
+}
+
+// HandleAddressListSuccessfully sets up the test server to respond to a ListAddresses request.
+func HandleAddressListSuccessfully(t *testing.T) {
+	th.Mux.HandleFunc("/servers/asdfasdfasdf/ips", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "GET")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+
+		w.Header().Add("Content-Type", "application/json")
+		fmt.Fprintf(w, `{
+			"addresses": {
+				"public": [
+				{
+					"version": 4,
+					"addr": "50.56.176.35"
+				},
+				{
+					"version": 6,
+					"addr": "2001:4800:780e:510:be76:4eff:fe04:84a8"
+				}
+				],
+				"private": [
+				{
+					"version": 4,
+					"addr": "10.180.3.155"
+				}
+				]
+			}
+		}`)
+	})
+}
+
+// ListNetworkAddressesExpected represents an expected repsonse from a ListAddressesByNetwork request.
+var ListNetworkAddressesExpected = []servers.Address{
+	{
+		Version: 4,
+		Address: "50.56.176.35",
+	},
+	{
+		Version: 6,
+		Address: "2001:4800:780e:510:be76:4eff:fe04:84a8",
+	},
+}
+
+// HandleNetworkAddressListSuccessfully sets up the test server to respond to a ListAddressesByNetwork request.
+func HandleNetworkAddressListSuccessfully(t *testing.T) {
+	th.Mux.HandleFunc("/servers/asdfasdfasdf/ips/public", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "GET")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+
+		w.Header().Add("Content-Type", "application/json")
+		fmt.Fprintf(w, `{
+			"public": [
+			{
+				"version": 4,
+				"addr": "50.56.176.35"
+				},
+				{
+					"version": 6,
+					"addr": "2001:4800:780e:510:be76:4eff:fe04:84a8"
+				}
+			]
+			}`)
+	})
+}
+
+// HandleCreateServerImageSuccessfully sets up the test server to respond to a TestCreateServerImage request.
+func HandleCreateServerImageSuccessfully(t *testing.T) {
+	th.Mux.HandleFunc("/servers/serverimage/action", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "POST")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+		w.Header().Add("Location", "https://0.0.0.0/images/xxxx-xxxxx-xxxxx-xxxx")
+		w.WriteHeader(http.StatusAccepted)
+	})
+}
+
+// HandlePasswordGetSuccessfully sets up the test server to respond to a password Get request.
+func HandlePasswordGetSuccessfully(t *testing.T) {
+	th.Mux.HandleFunc("/servers/1234asdf/os-server-password", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "GET")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+		th.TestHeader(t, r, "Accept", "application/json")
+
+		fmt.Fprintf(w, ServerPasswordBody)
+	})
+}
diff --git a/openstack/compute/v2/servers/testing/requests_test.go b/openstack/compute/v2/servers/testing/requests_test.go
new file mode 100644
index 0000000..7db6b93
--- /dev/null
+++ b/openstack/compute/v2/servers/testing/requests_test.go
@@ -0,0 +1,412 @@
+package testing
+
+import (
+	"encoding/base64"
+	"encoding/json"
+	"net/http"
+	"testing"
+
+	"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
+	"github.com/gophercloud/gophercloud/pagination"
+	th "github.com/gophercloud/gophercloud/testhelper"
+	"github.com/gophercloud/gophercloud/testhelper/client"
+)
+
+func TestListServers(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+	HandleServerListSuccessfully(t)
+
+	pages := 0
+	err := servers.List(client.ServiceClient(), servers.ListOpts{}).EachPage(func(page pagination.Page) (bool, error) {
+		pages++
+
+		actual, err := servers.ExtractServers(page)
+		if err != nil {
+			return false, err
+		}
+
+		if len(actual) != 2 {
+			t.Fatalf("Expected 2 servers, got %d", len(actual))
+		}
+		th.CheckDeepEquals(t, ServerHerp, actual[0])
+		th.CheckDeepEquals(t, ServerDerp, actual[1])
+
+		return true, nil
+	})
+
+	th.AssertNoErr(t, err)
+
+	if pages != 1 {
+		t.Errorf("Expected 1 page, saw %d", pages)
+	}
+}
+
+func TestListAllServers(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+	HandleServerListSuccessfully(t)
+
+	allPages, err := servers.List(client.ServiceClient(), servers.ListOpts{}).AllPages()
+	th.AssertNoErr(t, err)
+	actual, err := servers.ExtractServers(allPages)
+	th.AssertNoErr(t, err)
+	th.CheckDeepEquals(t, ServerHerp, actual[0])
+	th.CheckDeepEquals(t, ServerDerp, actual[1])
+}
+
+func TestCreateServer(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+	HandleServerCreationSuccessfully(t, SingleServerBody)
+
+	actual, err := servers.Create(client.ServiceClient(), servers.CreateOpts{
+		Name:      "derp",
+		ImageRef:  "f90f6034-2570-4974-8351-6b49732ef2eb",
+		FlavorRef: "1",
+	}).Extract()
+	th.AssertNoErr(t, err)
+
+	th.CheckDeepEquals(t, ServerDerp, *actual)
+}
+
+func TestCreateServerWithCustomField(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+	HandleServerCreationWithCustomFieldSuccessfully(t, SingleServerBody)
+
+	actual, err := servers.Create(client.ServiceClient(), CreateOptsWithCustomField{
+		CreateOpts: servers.CreateOpts{
+			Name:      "derp",
+			ImageRef:  "f90f6034-2570-4974-8351-6b49732ef2eb",
+			FlavorRef: "1",
+		},
+		Foo: "bar",
+	}).Extract()
+	th.AssertNoErr(t, err)
+
+	th.CheckDeepEquals(t, ServerDerp, *actual)
+}
+
+func TestDeleteServer(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+	HandleServerDeletionSuccessfully(t)
+
+	res := servers.Delete(client.ServiceClient(), "asdfasdfasdf")
+	th.AssertNoErr(t, res.Err)
+}
+
+func TestForceDeleteServer(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+	HandleServerForceDeletionSuccessfully(t)
+
+	res := servers.ForceDelete(client.ServiceClient(), "asdfasdfasdf")
+	th.AssertNoErr(t, res.Err)
+}
+
+func TestGetServer(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+	HandleServerGetSuccessfully(t)
+
+	client := client.ServiceClient()
+	actual, err := servers.Get(client, "1234asdf").Extract()
+	if err != nil {
+		t.Fatalf("Unexpected Get error: %v", err)
+	}
+
+	th.CheckDeepEquals(t, ServerDerp, *actual)
+}
+
+func TestUpdateServer(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+	HandleServerUpdateSuccessfully(t)
+
+	client := client.ServiceClient()
+	actual, err := servers.Update(client, "1234asdf", servers.UpdateOpts{Name: "new-name"}).Extract()
+	if err != nil {
+		t.Fatalf("Unexpected Update error: %v", err)
+	}
+
+	th.CheckDeepEquals(t, ServerDerp, *actual)
+}
+
+func TestChangeServerAdminPassword(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+	HandleAdminPasswordChangeSuccessfully(t)
+
+	res := servers.ChangeAdminPassword(client.ServiceClient(), "1234asdf", "new-password")
+	th.AssertNoErr(t, res.Err)
+}
+
+func TestGetPassword(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+	HandlePasswordGetSuccessfully(t)
+
+	res := servers.GetPassword(client.ServiceClient(), "1234asdf")
+	th.AssertNoErr(t, res.Err)
+}
+
+func TestRebootServer(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+	HandleRebootSuccessfully(t)
+
+	res := servers.Reboot(client.ServiceClient(), "1234asdf", &servers.RebootOpts{
+		Type: servers.SoftReboot,
+	})
+	th.AssertNoErr(t, res.Err)
+}
+
+func TestRebuildServer(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+	HandleRebuildSuccessfully(t, SingleServerBody)
+
+	opts := servers.RebuildOpts{
+		Name:       "new-name",
+		AdminPass:  "swordfish",
+		ImageID:    "http://104.130.131.164:8774/fcad67a6189847c4aecfa3c81a05783b/images/f90f6034-2570-4974-8351-6b49732ef2eb",
+		AccessIPv4: "1.2.3.4",
+	}
+
+	actual, err := servers.Rebuild(client.ServiceClient(), "1234asdf", opts).Extract()
+	th.AssertNoErr(t, err)
+
+	th.CheckDeepEquals(t, ServerDerp, *actual)
+}
+
+func TestResizeServer(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+
+	th.Mux.HandleFunc("/servers/1234asdf/action", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "POST")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+		th.TestJSONRequest(t, r, `{ "resize": { "flavorRef": "2" } }`)
+
+		w.WriteHeader(http.StatusAccepted)
+	})
+
+	res := servers.Resize(client.ServiceClient(), "1234asdf", servers.ResizeOpts{FlavorRef: "2"})
+	th.AssertNoErr(t, res.Err)
+}
+
+func TestConfirmResize(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+
+	th.Mux.HandleFunc("/servers/1234asdf/action", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "POST")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+		th.TestJSONRequest(t, r, `{ "confirmResize": null }`)
+
+		w.WriteHeader(http.StatusNoContent)
+	})
+
+	res := servers.ConfirmResize(client.ServiceClient(), "1234asdf")
+	th.AssertNoErr(t, res.Err)
+}
+
+func TestRevertResize(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+
+	th.Mux.HandleFunc("/servers/1234asdf/action", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "POST")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+		th.TestJSONRequest(t, r, `{ "revertResize": null }`)
+
+		w.WriteHeader(http.StatusAccepted)
+	})
+
+	res := servers.RevertResize(client.ServiceClient(), "1234asdf")
+	th.AssertNoErr(t, res.Err)
+}
+
+func TestRescue(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+
+	HandleServerRescueSuccessfully(t)
+
+	res := servers.Rescue(client.ServiceClient(), "1234asdf", servers.RescueOpts{
+		AdminPass: "1234567890",
+	})
+	th.AssertNoErr(t, res.Err)
+	adminPass, _ := res.Extract()
+	th.AssertEquals(t, "1234567890", adminPass)
+}
+
+func TestGetMetadatum(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+
+	HandleMetadatumGetSuccessfully(t)
+
+	expected := map[string]string{"foo": "bar"}
+	actual, err := servers.Metadatum(client.ServiceClient(), "1234asdf", "foo").Extract()
+	th.AssertNoErr(t, err)
+	th.AssertDeepEquals(t, expected, actual)
+}
+
+func TestCreateMetadatum(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+
+	HandleMetadatumCreateSuccessfully(t)
+
+	expected := map[string]string{"foo": "bar"}
+	actual, err := servers.CreateMetadatum(client.ServiceClient(), "1234asdf", servers.MetadatumOpts{"foo": "bar"}).Extract()
+	th.AssertNoErr(t, err)
+	th.AssertDeepEquals(t, expected, actual)
+}
+
+func TestDeleteMetadatum(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+
+	HandleMetadatumDeleteSuccessfully(t)
+
+	err := servers.DeleteMetadatum(client.ServiceClient(), "1234asdf", "foo").ExtractErr()
+	th.AssertNoErr(t, err)
+}
+
+func TestGetMetadata(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+
+	HandleMetadataGetSuccessfully(t)
+
+	expected := map[string]string{"foo": "bar", "this": "that"}
+	actual, err := servers.Metadata(client.ServiceClient(), "1234asdf").Extract()
+	th.AssertNoErr(t, err)
+	th.AssertDeepEquals(t, expected, actual)
+}
+
+func TestResetMetadata(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+
+	HandleMetadataResetSuccessfully(t)
+
+	expected := map[string]string{"foo": "bar", "this": "that"}
+	actual, err := servers.ResetMetadata(client.ServiceClient(), "1234asdf", servers.MetadataOpts{
+		"foo":  "bar",
+		"this": "that",
+	}).Extract()
+	th.AssertNoErr(t, err)
+	th.AssertDeepEquals(t, expected, actual)
+}
+
+func TestUpdateMetadata(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+
+	HandleMetadataUpdateSuccessfully(t)
+
+	expected := map[string]string{"foo": "baz", "this": "those"}
+	actual, err := servers.UpdateMetadata(client.ServiceClient(), "1234asdf", servers.MetadataOpts{
+		"foo":  "baz",
+		"this": "those",
+	}).Extract()
+	th.AssertNoErr(t, err)
+	th.AssertDeepEquals(t, expected, actual)
+}
+
+func TestListAddresses(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+	HandleAddressListSuccessfully(t)
+
+	expected := ListAddressesExpected
+	pages := 0
+	err := servers.ListAddresses(client.ServiceClient(), "asdfasdfasdf").EachPage(func(page pagination.Page) (bool, error) {
+		pages++
+
+		actual, err := servers.ExtractAddresses(page)
+		th.AssertNoErr(t, err)
+
+		if len(actual) != 2 {
+			t.Fatalf("Expected 2 networks, got %d", len(actual))
+		}
+		th.CheckDeepEquals(t, expected, actual)
+
+		return true, nil
+	})
+	th.AssertNoErr(t, err)
+	th.CheckEquals(t, 1, pages)
+}
+
+func TestListAddressesByNetwork(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+	HandleNetworkAddressListSuccessfully(t)
+
+	expected := ListNetworkAddressesExpected
+	pages := 0
+	err := servers.ListAddressesByNetwork(client.ServiceClient(), "asdfasdfasdf", "public").EachPage(func(page pagination.Page) (bool, error) {
+		pages++
+
+		actual, err := servers.ExtractNetworkAddresses(page)
+		th.AssertNoErr(t, err)
+
+		if len(actual) != 2 {
+			t.Fatalf("Expected 2 addresses, got %d", len(actual))
+		}
+		th.CheckDeepEquals(t, expected, actual)
+
+		return true, nil
+	})
+	th.AssertNoErr(t, err)
+	th.CheckEquals(t, 1, pages)
+}
+
+func TestCreateServerImage(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+	HandleCreateServerImageSuccessfully(t)
+
+	_, err := servers.CreateImage(client.ServiceClient(), "serverimage", servers.CreateImageOpts{Name: "test"}).ExtractImageID()
+	th.AssertNoErr(t, err)
+}
+
+func TestMarshalPersonality(t *testing.T) {
+	name := "/etc/test"
+	contents := []byte("asdfasdf")
+
+	personality := servers.Personality{
+		&servers.File{
+			Path:     name,
+			Contents: contents,
+		},
+	}
+
+	data, err := json.Marshal(personality)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	var actual []map[string]string
+	err = json.Unmarshal(data, &actual)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if len(actual) != 1 {
+		t.Fatal("expected personality length 1")
+	}
+
+	if actual[0]["path"] != name {
+		t.Fatal("file path incorrect")
+	}
+
+	if actual[0]["contents"] != base64.StdEncoding.EncodeToString(contents) {
+		t.Fatal("file contents incorrect")
+	}
+}
diff --git a/openstack/compute/v2/servers/testing/results_test.go b/openstack/compute/v2/servers/testing/results_test.go
new file mode 100644
index 0000000..e5334f0
--- /dev/null
+++ b/openstack/compute/v2/servers/testing/results_test.go
@@ -0,0 +1,98 @@
+package testing
+
+import (
+	"crypto/rsa"
+	"encoding/json"
+	"fmt"
+	"testing"
+
+	"github.com/gophercloud/gophercloud"
+	"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
+	th "github.com/gophercloud/gophercloud/testhelper"
+	"golang.org/x/crypto/ssh"
+)
+
+// Fail - No password in JSON.
+func TestExtractPassword_no_pwd_data(t *testing.T) {
+
+	var dejson interface{}
+	err := json.Unmarshal([]byte(`{ "Crappy data": ".-.-." }`), &dejson)
+	if err != nil {
+		t.Fatalf("%s", err)
+	}
+	resp := servers.GetPasswordResult{gophercloud.Result{Body: dejson}}
+
+	pwd, err := resp.ExtractPassword(nil)
+	th.AssertEquals(t, pwd, "")
+}
+
+// Ok - return encrypted password when no private key is given.
+func TestExtractPassword_encrypted_pwd(t *testing.T) {
+
+	var dejson interface{}
+	sejson := []byte(`{"password":"PP8EnwPO9DhEc8+O/6CKAkPF379mKsUsfFY6yyw0734XXvKsSdV9KbiHQ2hrBvzeZxtGMrlFaikVunCRizyLLWLMuOi4hoH+qy9F9sQid61gQIGkxwDAt85d/7Eau2/KzorFnZhgxArl7IiqJ67X6xjKkR3zur+Yp3V/mtVIehpPYIaAvPbcp2t4mQXl1I9J8yrQfEZOctLL1L4heDEVXnxvNihVLK6pivlVggp6SZCtjj9cduZGrYGsxsOCso1dqJQr7GCojfwvuLOoG0OYwEGuWVTZppxWxi/q1QgeHFhGKA5QUXlz7pS71oqpjYsTeViuHnfvlqb5TVYZpQ1haw=="}`)
+
+	err := json.Unmarshal(sejson, &dejson)
+	fmt.Printf("%v\n", dejson)
+	if err != nil {
+		t.Fatalf("%s", err)
+	}
+	resp := servers.GetPasswordResult{gophercloud.Result{Body: dejson}}
+
+	pwd, err := resp.ExtractPassword(nil)
+	th.AssertNoErr(t, err)
+	th.AssertEquals(t, "PP8EnwPO9DhEc8+O/6CKAkPF379mKsUsfFY6yyw0734XXvKsSdV9KbiHQ2hrBvzeZxtGMrlFaikVunCRizyLLWLMuOi4hoH+qy9F9sQid61gQIGkxwDAt85d/7Eau2/KzorFnZhgxArl7IiqJ67X6xjKkR3zur+Yp3V/mtVIehpPYIaAvPbcp2t4mQXl1I9J8yrQfEZOctLL1L4heDEVXnxvNihVLK6pivlVggp6SZCtjj9cduZGrYGsxsOCso1dqJQr7GCojfwvuLOoG0OYwEGuWVTZppxWxi/q1QgeHFhGKA5QUXlz7pS71oqpjYsTeViuHnfvlqb5TVYZpQ1haw==", pwd)
+}
+
+// Ok - return decrypted password when private key is given.
+// Decrytion can be verified by:
+//   echo "<enc_pwd>" | base64 -D | openssl rsautl -decrypt -inkey <privateKey.pem>
+func TestExtractPassword_decrypted_pwd(t *testing.T) {
+
+	privateKey, err := ssh.ParseRawPrivateKey([]byte(`
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEAo1ODZgwMVdTJYim9UYuYhowoPMhGEuV5IRZjcJ315r7RBSC+
+yEiBb1V+jhf+P8fzAyU35lkBzZGDr7E3jxSesbOuYT8cItQS4ErUnI1LGuqvMxwv
+X3GMyE/HmOcaiODF1XZN3Ur5pMJdVknnmczgUsW0hT98Udrh3MQn9WSuh/6LRy6+
+x1QsKHOCLFPnkhWa3LKyxmpQq/Gvhz+6NLe+gt8MFullA5mKQxBJ/K6laVHeaMlw
+JG3GCX0EZhRlvzoV8koIBKZtbKFolFr8ZtxBm3R5LvnyrtOvp22sa+xeItUT5kG1
+ZnbGNdK87oYW+VigEUfzT/+8R1i6E2QIXoeZiQIDAQABAoIBAQCVZ70IqbbTAW8j
+RAlyQh/J3Qal65LmkFJJKUDX8TfT1/Q/G6BKeMEmxm+Zrmsfj1pHI1HKftt+YEG1
+g4jOc09kQXkgbmnfll6aHPn3J+1vdwXD3GGdjrL5PrnYrngAhJWU2r8J0x8hT8ew
+OrUJZXhDX6XuSpAAFRmOKUZgXbSmo4X+LZX76ACnarselJt5FL724ECvpWJ7xxC4
+FMzvp4RqMmNFvv/Uq9lE/EmoSk4dviYyIZZ16DbDNyc9k/sGqCAMktCEwZ3EQm//
+S5bkNhgP6oUXjluWy53aPRgykEylgDWo5SSdSEyKnw/fciU0xdprA9JrBGIcTyHS
+/k2kgD4xAoGBANTkJ88Q0YrxX3fZNZVqcn00XKTxPGmxN5LRs7eV743q30AxK5Db
+QU8iwaAA1IKUWV5DLhgUTNsDCOPUPue4aOSBD3/sj+WEmvIhj7afDL5didkYHsqf
+fDnhFHq7y/3i57d428C7BwwR79pGWVyi7vH3pfu9A1iwl1aNOae+zvbVAoGBAMRm
+AmwQ9fJ3Qc44jysFK/yliLRGdShjkMMah5G3JlrelwfPtwPwEL2EHHhJB/C1acMs
+n6Q6RaoF6WNSZUY65ksQg7aPOYf2X0FTFwQJvwDJ4qlWjmq7w+tQ0AoGJG+dVUmQ
+zHZ/Y+HokSXzz9c4oevk4v/rMgAQ00WHrTdtIhnlAoGBALIJJ72D7CkNGHCq5qPQ
+xHQukPejgolFGhufYXM7YX3GmPMe67cVlTVv9Isxhoa5N0+cUPT0LR3PGOUm/4Bb
+eOT3hZXOqLwhvE6XgI8Rzd95bClwgXekDoh80dqeKMdmta961BQGlKskaPiacmsF
+G1yhZV70P9Mwwy8vpbLB4GUNAoGAbTwbjsWkNfa0qCF3J8NZoszjCvnBQfSW2J1R
+1+8ZKyNwt0yFi3Ajr3TibNiZzPzp1T9lj29FvfpJxA9Y+sXZvthxmcFxizix5GB1
+ha5yCNtA8VSOI7lJkAFDpL+j1lyYyjD6N9JE2KqEyKoh6J+8F7sXsqW7CqRRDfQX
+mKNfey0CgYEAxcEoNoADN2hRl7qY9rbQfVvQb3RkoQkdHhl9gpLFCcV32IP8R4xg
+09NbQK5OmgcIuZhLVNzTmUHJbabEGeXqIFIV0DsqECAt3WzbDyKQO23VJysFD46c
+KSde3I0ybDz7iS2EtceKB7m4C0slYd+oBkm4efuF00rCOKDwpFq45m0=
+-----END RSA PRIVATE KEY-----
+`))
+	if err != nil {
+		t.Fatalf("Error parsing private key: %s\n", err)
+	}
+
+	var dejson interface{}
+	sejson := []byte(`{"password":"PP8EnwPO9DhEc8+O/6CKAkPF379mKsUsfFY6yyw0734XXvKsSdV9KbiHQ2hrBvzeZxtGMrlFaikVunCRizyLLWLMuOi4hoH+qy9F9sQid61gQIGkxwDAt85d/7Eau2/KzorFnZhgxArl7IiqJ67X6xjKkR3zur+Yp3V/mtVIehpPYIaAvPbcp2t4mQXl1I9J8yrQfEZOctLL1L4heDEVXnxvNihVLK6pivlVggp6SZCtjj9cduZGrYGsxsOCso1dqJQr7GCojfwvuLOoG0OYwEGuWVTZppxWxi/q1QgeHFhGKA5QUXlz7pS71oqpjYsTeViuHnfvlqb5TVYZpQ1haw=="}`)
+
+	err = json.Unmarshal(sejson, &dejson)
+	fmt.Printf("%v\n", dejson)
+	if err != nil {
+		t.Fatalf("%s", err)
+	}
+	resp := servers.GetPasswordResult{gophercloud.Result{Body: dejson}}
+
+	pwd, err := resp.ExtractPassword(privateKey.(*rsa.PrivateKey))
+	th.AssertNoErr(t, err)
+	th.AssertEquals(t, "ruZKK0tqxRfYm5t7lSJq", pwd)
+}