images service v2 port from rackpsace/gophercloud (#171)
* CheckByteArrayEquals funcs
* direct port from rackspace/gophercloud with minor additions to get unit tests passing
* new package for uploading and downloading image data
* updates to make imageservice v2 consistent with the rest of gophercloud/gophercloud
* add image service v2 client
diff --git a/openstack/imageservice/v2/members/testing/fixtures.go b/openstack/imageservice/v2/members/testing/fixtures.go
new file mode 100644
index 0000000..c08fc5e
--- /dev/null
+++ b/openstack/imageservice/v2/members/testing/fixtures.go
@@ -0,0 +1,138 @@
+package testing
+
+import (
+ "fmt"
+ "net/http"
+ "testing"
+
+ th "github.com/gophercloud/gophercloud/testhelper"
+ fakeclient "github.com/gophercloud/gophercloud/testhelper/client"
+)
+
+// HandleCreateImageMemberSuccessfully setup
+func HandleCreateImageMemberSuccessfully(t *testing.T) {
+ th.Mux.HandleFunc("/images/da3b75d9-3f4a-40e7-8a2c-bfab23927dea/members", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "POST")
+ th.TestHeader(t, r, "X-Auth-Token", fakeclient.TokenID)
+
+ th.TestJSONRequest(t, r, `{"member": "8989447062e04a818baf9e073fd04fa7"}`)
+
+ w.WriteHeader(http.StatusOK)
+ fmt.Fprintf(w, `{
+ "created_at": "2013-09-20T19:22:19Z",
+ "image_id": "da3b75d9-3f4a-40e7-8a2c-bfab23927dea",
+ "member_id": "8989447062e04a818baf9e073fd04fa7",
+ "schema": "/v2/schemas/member",
+ "status": "pending",
+ "updated_at": "2013-09-20T19:25:31Z"
+ }`)
+
+ })
+}
+
+// HandleImageMemberList happy path setup
+func HandleImageMemberList(t *testing.T) {
+ th.Mux.HandleFunc("/images/da3b75d9-3f4a-40e7-8a2c-bfab23927dea/members", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "GET")
+ th.TestHeader(t, r, "X-Auth-Token", fakeclient.TokenID)
+
+ w.Header().Add("Content-Type", "application/json")
+ fmt.Fprintf(w, `{
+ "members": [
+ {
+ "created_at": "2013-10-07T17:58:03Z",
+ "image_id": "da3b75d9-3f4a-40e7-8a2c-bfab23927dea",
+ "member_id": "123456789",
+ "schema": "/v2/schemas/member",
+ "status": "pending",
+ "updated_at": "2013-10-07T17:58:03Z"
+ },
+ {
+ "created_at": "2013-10-07T17:58:55Z",
+ "image_id": "da3b75d9-3f4a-40e7-8a2c-bfab23927dea",
+ "member_id": "987654321",
+ "schema": "/v2/schemas/member",
+ "status": "accepted",
+ "updated_at": "2013-10-08T12:08:55Z"
+ }
+ ],
+ "schema": "/v2/schemas/members"
+ }`)
+ })
+}
+
+// HandleImageMemberEmptyList happy path setup
+func HandleImageMemberEmptyList(t *testing.T) {
+ th.Mux.HandleFunc("/images/da3b75d9-3f4a-40e7-8a2c-bfab23927dea/members", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "GET")
+ th.TestHeader(t, r, "X-Auth-Token", fakeclient.TokenID)
+
+ w.Header().Add("Content-Type", "application/json")
+ fmt.Fprintf(w, `{
+ "members": [],
+ "schema": "/v2/schemas/members"
+ }`)
+ })
+}
+
+// HandleImageMemberDetails setup
+func HandleImageMemberDetails(t *testing.T) {
+ th.Mux.HandleFunc("/images/da3b75d9-3f4a-40e7-8a2c-bfab23927dea/members/8989447062e04a818baf9e073fd04fa7", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "GET")
+ th.TestHeader(t, r, "X-Auth-Token", fakeclient.TokenID)
+
+ w.WriteHeader(http.StatusOK)
+ fmt.Fprintf(w, `{
+ "status": "pending",
+ "created_at": "2013-11-26T07:21:21Z",
+ "updated_at": "2013-11-26T07:21:21Z",
+ "image_id": "da3b75d9-3f4a-40e7-8a2c-bfab23927dea",
+ "member_id": "8989447062e04a818baf9e073fd04fa7",
+ "schema": "/v2/schemas/member"
+ }`)
+ })
+}
+
+// HandleImageMemberDeleteSuccessfully setup
+func HandleImageMemberDeleteSuccessfully(t *testing.T) *CallsCounter {
+ var counter CallsCounter
+ th.Mux.HandleFunc("/images/da3b75d9-3f4a-40e7-8a2c-bfab23927dea/members/8989447062e04a818baf9e073fd04fa7", func(w http.ResponseWriter, r *http.Request) {
+ counter.Counter = counter.Counter + 1
+
+ th.TestMethod(t, r, "DELETE")
+ th.TestHeader(t, r, "X-Auth-Token", fakeclient.TokenID)
+
+ w.WriteHeader(http.StatusNoContent)
+ })
+ return &counter
+}
+
+// HandleImageMemberUpdate setup
+func HandleImageMemberUpdate(t *testing.T) *CallsCounter {
+ var counter CallsCounter
+ th.Mux.HandleFunc("/images/da3b75d9-3f4a-40e7-8a2c-bfab23927dea/members/8989447062e04a818baf9e073fd04fa7", func(w http.ResponseWriter, r *http.Request) {
+ counter.Counter = counter.Counter + 1
+
+ th.TestMethod(t, r, "PUT")
+ th.TestHeader(t, r, "X-Auth-Token", fakeclient.TokenID)
+
+ th.TestJSONRequest(t, r, `{"status": "accepted"}`)
+
+ w.WriteHeader(http.StatusOK)
+
+ fmt.Fprintf(w, `{
+ "status": "accepted",
+ "created_at": "2013-11-26T07:21:21Z",
+ "updated_at": "2013-11-26T07:21:21Z",
+ "image_id": "da3b75d9-3f4a-40e7-8a2c-bfab23927dea",
+ "member_id": "8989447062e04a818baf9e073fd04fa7",
+ "schema": "/v2/schemas/member"
+ }`)
+ })
+ return &counter
+}
+
+// CallsCounter for checking if request handler was called at all
+type CallsCounter struct {
+ Counter int
+}
diff --git a/openstack/imageservice/v2/members/testing/requests_test.go b/openstack/imageservice/v2/members/testing/requests_test.go
new file mode 100644
index 0000000..04624c9
--- /dev/null
+++ b/openstack/imageservice/v2/members/testing/requests_test.go
@@ -0,0 +1,172 @@
+package testing
+
+import (
+ "testing"
+ "time"
+
+ "github.com/gophercloud/gophercloud/openstack/imageservice/v2/members"
+ "github.com/gophercloud/gophercloud/pagination"
+ th "github.com/gophercloud/gophercloud/testhelper"
+ fakeclient "github.com/gophercloud/gophercloud/testhelper/client"
+)
+
+const createdAtString = "2013-09-20T19:22:19Z"
+const updatedAtString = "2013-09-20T19:25:31Z"
+
+func TestCreateMemberSuccessfully(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ HandleCreateImageMemberSuccessfully(t)
+ im, err := members.Create(fakeclient.ServiceClient(), "da3b75d9-3f4a-40e7-8a2c-bfab23927dea",
+ "8989447062e04a818baf9e073fd04fa7").Extract()
+ th.AssertNoErr(t, err)
+
+ createdAt, err := time.Parse(time.RFC3339, createdAtString)
+ th.AssertNoErr(t, err)
+
+ updatedAt, err := time.Parse(time.RFC3339, updatedAtString)
+ th.AssertNoErr(t, err)
+
+ th.AssertDeepEquals(t, members.Member{
+ CreatedAt: createdAt,
+ ImageID: "da3b75d9-3f4a-40e7-8a2c-bfab23927dea",
+ MemberID: "8989447062e04a818baf9e073fd04fa7",
+ Schema: "/v2/schemas/member",
+ Status: "pending",
+ UpdatedAt: updatedAt,
+ }, *im)
+
+}
+
+func TestMemberListSuccessfully(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ HandleImageMemberList(t)
+
+ pager := members.List(fakeclient.ServiceClient(), "da3b75d9-3f4a-40e7-8a2c-bfab23927dea")
+ t.Logf("Pager state %v", pager)
+ count, pages := 0, 0
+ err := pager.EachPage(func(page pagination.Page) (bool, error) {
+ pages++
+ t.Logf("Page %v", page)
+ members, err := members.ExtractMembers(page)
+ if err != nil {
+ return false, err
+ }
+
+ for _, i := range members {
+ t.Logf("%s\t%s\t%s\t%s\t\n", i.ImageID, i.MemberID, i.Status, i.Schema)
+ count++
+ }
+
+ return true, nil
+ })
+
+ th.AssertNoErr(t, err)
+ th.AssertEquals(t, 1, pages)
+ th.AssertEquals(t, 2, count)
+}
+
+func TestMemberListEmpty(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ HandleImageMemberEmptyList(t)
+
+ pager := members.List(fakeclient.ServiceClient(), "da3b75d9-3f4a-40e7-8a2c-bfab23927dea")
+ t.Logf("Pager state %v", pager)
+ count, pages := 0, 0
+ err := pager.EachPage(func(page pagination.Page) (bool, error) {
+ pages++
+ t.Logf("Page %v", page)
+ members, err := members.ExtractMembers(page)
+ if err != nil {
+ return false, err
+ }
+
+ for _, i := range members {
+ t.Logf("%s\t%s\t%s\t%s\t\n", i.ImageID, i.MemberID, i.Status, i.Schema)
+ count++
+ }
+
+ return true, nil
+ })
+
+ th.AssertNoErr(t, err)
+ th.AssertEquals(t, 0, pages)
+ th.AssertEquals(t, 0, count)
+}
+
+func TestShowMemberDetails(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ HandleImageMemberDetails(t)
+ md, err := members.Get(fakeclient.ServiceClient(),
+ "da3b75d9-3f4a-40e7-8a2c-bfab23927dea",
+ "8989447062e04a818baf9e073fd04fa7").Extract()
+
+ th.AssertNoErr(t, err)
+ if md == nil {
+ t.Errorf("Expected non-nil value for md")
+ }
+
+ createdAt, err := time.Parse(time.RFC3339, "2013-11-26T07:21:21Z")
+ th.AssertNoErr(t, err)
+
+ updatedAt, err := time.Parse(time.RFC3339, "2013-11-26T07:21:21Z")
+ th.AssertNoErr(t, err)
+
+ th.AssertDeepEquals(t, members.Member{
+ CreatedAt: createdAt,
+ ImageID: "da3b75d9-3f4a-40e7-8a2c-bfab23927dea",
+ MemberID: "8989447062e04a818baf9e073fd04fa7",
+ Schema: "/v2/schemas/member",
+ Status: "pending",
+ UpdatedAt: updatedAt,
+ }, *md)
+}
+
+func TestDeleteMember(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ counter := HandleImageMemberDeleteSuccessfully(t)
+
+ result := members.Delete(fakeclient.ServiceClient(), "da3b75d9-3f4a-40e7-8a2c-bfab23927dea",
+ "8989447062e04a818baf9e073fd04fa7")
+ th.AssertEquals(t, 1, counter.Counter)
+ th.AssertNoErr(t, result.Err)
+}
+
+func TestMemberUpdateSuccessfully(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ counter := HandleImageMemberUpdate(t)
+ im, err := members.Update(fakeclient.ServiceClient(), "da3b75d9-3f4a-40e7-8a2c-bfab23927dea",
+ "8989447062e04a818baf9e073fd04fa7",
+ members.UpdateOpts{
+ Status: "accepted",
+ }).Extract()
+ th.AssertEquals(t, 1, counter.Counter)
+ th.AssertNoErr(t, err)
+
+ createdAt, err := time.Parse(time.RFC3339, "2013-11-26T07:21:21Z")
+ th.AssertNoErr(t, err)
+
+ updatedAt, err := time.Parse(time.RFC3339, "2013-11-26T07:21:21Z")
+ th.AssertNoErr(t, err)
+
+ th.AssertDeepEquals(t, members.Member{
+ CreatedAt: createdAt,
+ ImageID: "da3b75d9-3f4a-40e7-8a2c-bfab23927dea",
+ MemberID: "8989447062e04a818baf9e073fd04fa7",
+ Schema: "/v2/schemas/member",
+ Status: "accepted",
+ UpdatedAt: updatedAt,
+ }, *im)
+
+}