From ffbaa31af74b711913e5a3fe5814af4b60d5aa61 Mon Sep 17 00:00:00 2001 From: Andrei Ozerov Date: Thu, 3 Jan 2019 15:09:10 +0300 Subject: [PATCH] Resell V2 - add Keypairs List method) Add the "keypairs" package with a List method and a basic Keypair structure. Add tests and doc example. --- selvpcclient/resell/v2/keypairs/doc.go | 15 ++ selvpcclient/resell/v2/keypairs/requests.go | 34 ++++ selvpcclient/resell/v2/keypairs/schemas.go | 18 +++ .../resell/v2/keypairs/testing/fixtures.go | 78 +++++++++ .../v2/keypairs/testing/requests_test.go | 151 ++++++++++++++++++ 5 files changed, 296 insertions(+) create mode 100644 selvpcclient/resell/v2/keypairs/doc.go create mode 100644 selvpcclient/resell/v2/keypairs/requests.go create mode 100644 selvpcclient/resell/v2/keypairs/schemas.go create mode 100644 selvpcclient/resell/v2/keypairs/testing/fixtures.go create mode 100644 selvpcclient/resell/v2/keypairs/testing/requests_test.go diff --git a/selvpcclient/resell/v2/keypairs/doc.go b/selvpcclient/resell/v2/keypairs/doc.go new file mode 100644 index 0000000..b263210 --- /dev/null +++ b/selvpcclient/resell/v2/keypairs/doc.go @@ -0,0 +1,15 @@ +/* +Package keypairs provides the ability to retrieve and manage keypairs through +the Resell v2 API. + +Example of getting keypairs in the current domain + + allKeypairs, _, err = keypairs.List(context, resellClient) + if err != nil { + log.Fatal(err) + } + for _, myKeypair := range allKeypairs { + fmt.Println(myKeypair) + } +*/ +package keypairs diff --git a/selvpcclient/resell/v2/keypairs/requests.go b/selvpcclient/resell/v2/keypairs/requests.go new file mode 100644 index 0000000..b31f53e --- /dev/null +++ b/selvpcclient/resell/v2/keypairs/requests.go @@ -0,0 +1,34 @@ +package keypairs + +import ( + "context" + "net/http" + "strings" + + "github.com/selectel/go-selvpcclient/selvpcclient" +) + +const resourceURL = "keypairs" + +// List gets a list of keypairs in the current domain. +func List(ctx context.Context, client *selvpcclient.ServiceClient) ([]*Keypair, *selvpcclient.ResponseResult, error) { + url := strings.Join([]string{client.Endpoint, resourceURL}, "/") + responseResult, err := client.DoRequest(ctx, http.MethodGet, url, nil) + if err != nil { + return nil, nil, err + } + if responseResult.Err != nil { + return nil, responseResult, responseResult.Err + } + + // Extract keypairs. from the response body. + var result struct { + Keypairs []*Keypair `json:"keypairs"` + } + err = responseResult.ExtractResult(&result) + if err != nil { + return nil, responseResult, err + } + + return result.Keypairs, responseResult, nil +} diff --git a/selvpcclient/resell/v2/keypairs/schemas.go b/selvpcclient/resell/v2/keypairs/schemas.go new file mode 100644 index 0000000..15ac41a --- /dev/null +++ b/selvpcclient/resell/v2/keypairs/schemas.go @@ -0,0 +1,18 @@ +package keypairs + +// Keypair represents a single Resell API Keypair. +type Keypair struct { + // Name contains a human-readable name for the keypair. + Name string `json:"name"` + + // PublicKey contains a public part of the keypair. + PublicKey string `json:"public_key"` + + // Regions contains a list of OpenStack Identity service regions where users + // can use this keypair. + Regions []string `json:"regions"` + + // UserID contains an ID of an OpenStack Identity service user that owns + // this keypair. + UserID string `json:"user_id"` +} diff --git a/selvpcclient/resell/v2/keypairs/testing/fixtures.go b/selvpcclient/resell/v2/keypairs/testing/fixtures.go new file mode 100644 index 0000000..c921b43 --- /dev/null +++ b/selvpcclient/resell/v2/keypairs/testing/fixtures.go @@ -0,0 +1,78 @@ +package testing + +import "github.com/selectel/go-selvpcclient/selvpcclient/resell/v2/keypairs" + +// TestListResponseRaw represents a raw response from List requests. +const TestListResponseRaw = ` +{ + "keypairs": [ + { + "name": "key0", + "public_key": "ssh-rsa AAABBBCCC user0@selectel.com", + "regions": [ + "ru-1", + "ru-2", + "ru-3" + ], + "user_id": "82a026cae2104e92b999dbe00cdb9435" + }, + { + "name": "key1", + "public_key": "ssh-rsa BBBAAACCC user1@example.org", + "regions": [ + "ru-1", + "ru-2" + ], + "user_id": "046ffcab518f430bb6fc50c5edcdd8db" + }, + { + "name": "key2", + "public_key": "ssh-rsa CCCAAABBB user2@selectel.com", + "regions": [ + "ru-3" + ], + "user_id": "6d7eb892ca98413e8621c6366c8416be" + } + ] +} +` + +// TestListResponseSingleRaw represents a raw response with a single keypair +// from the List requests. +const TestListResponseSingleRaw = ` +{ + "keypairs": [ + { + "name": "key2", + "public_key": "ssh-rsa CCCAAABBB user2@selectel.com", + "regions": [ + "ru-3" + ], + "user_id": "6d7eb892ca98413e8621c6366c8416be" + } + ] +} +` + +// TestListResponseSingle represents the unmarshalled TestListResponseSingleRaw +// response. +var TestListResponseSingle = []*keypairs.Keypair{ + { + Name: "key2", + PublicKey: "ssh-rsa CCCAAABBB user2@selectel.com", + Regions: []string{"ru-3"}, + UserID: "6d7eb892ca98413e8621c6366c8416be", + }, +} + +// TestManyKeypairsInvalidResponseRaw represents a raw invalid response from the +// List call. +const TestManyKeypairsInvalidResponseRaw = ` +{ + "keypairs": [ + { + "user_id": 123 + } + ] +} +` diff --git a/selvpcclient/resell/v2/keypairs/testing/requests_test.go b/selvpcclient/resell/v2/keypairs/testing/requests_test.go new file mode 100644 index 0000000..38fb6ae --- /dev/null +++ b/selvpcclient/resell/v2/keypairs/testing/requests_test.go @@ -0,0 +1,151 @@ +package testing + +import ( + "context" + "net/http" + "reflect" + "testing" + + "github.com/selectel/go-selvpcclient/selvpcclient/resell/v2/keypairs" + "github.com/selectel/go-selvpcclient/selvpcclient/testutils" +) + +func TestListKeypairs(t *testing.T) { + endpointCalled := false + + testEnv := testutils.SetupTestEnv() + defer testEnv.TearDownTestEnv() + testEnv.NewTestResellV2Client() + testutils.HandleReqWithoutBody(t, &testutils.HandleReqOpts{ + Mux: testEnv.Mux, + URL: "/resell/v2/keypairs", + RawResponse: TestListResponseRaw, + Method: http.MethodGet, + Status: http.StatusOK, + CallFlag: &endpointCalled, + }) + + ctx := context.Background() + actual, _, err := keypairs.List(ctx, testEnv.Client) + if err != nil { + t.Fatal(err) + } + if !endpointCalled { + t.Fatal("didn't get keypairs") + } + actualKind := reflect.TypeOf(actual).Kind() + if actualKind != reflect.Slice { + t.Errorf("expected Slice of pointers to keypairs, but got %v", actualKind) + } + if len(actual) != 3 { + t.Errorf("expected 3 keypairs, but got %d", len(actual)) + } +} + +func TestListKeypairsSingle(t *testing.T) { + endpointCalled := false + + testEnv := testutils.SetupTestEnv() + defer testEnv.TearDownTestEnv() + testEnv.NewTestResellV2Client() + testutils.HandleReqWithoutBody(t, &testutils.HandleReqOpts{ + Mux: testEnv.Mux, + URL: "/resell/v2/keypairs", + RawResponse: TestListResponseSingleRaw, + Method: http.MethodGet, + Status: http.StatusOK, + CallFlag: &endpointCalled, + }) + + ctx := context.Background() + actual, _, err := keypairs.List(ctx, testEnv.Client) + if err != nil { + t.Fatal(err) + } + expected := TestListResponseSingle + if !endpointCalled { + t.Fatal("endpoint wasn't called") + } + if !reflect.DeepEqual(actual, expected) { + t.Fatalf("expected %#v, but got %#v", expected, actual) + } +} + +func TestListKeypairsHTTPError(t *testing.T) { + endpointCalled := false + + testEnv := testutils.SetupTestEnv() + defer testEnv.TearDownTestEnv() + testEnv.NewTestResellV2Client() + testutils.HandleReqWithoutBody(t, &testutils.HandleReqOpts{ + Mux: testEnv.Mux, + URL: "/resell/v2/keypairs", + RawResponse: TestListResponseRaw, + Method: http.MethodGet, + Status: http.StatusBadGateway, + CallFlag: &endpointCalled, + }) + + ctx := context.Background() + allKeypairs, httpResponse, err := keypairs.List(ctx, testEnv.Client) + + if !endpointCalled { + t.Fatal("endpoint wasn't called") + } + if allKeypairs != nil { + t.Fatal("expected no keypairs from the List method") + } + if err == nil { + t.Fatal("expected error from the List method") + } + if httpResponse.StatusCode != http.StatusBadGateway { + t.Fatalf("expected %d status in the HTTP response, but got %d", + http.StatusBadGateway, httpResponse.StatusCode) + } +} + +func TestListKeypairsTimeoutError(t *testing.T) { + testEnv := testutils.SetupTestEnv() + testEnv.Server.Close() + defer testEnv.TearDownTestEnv() + testEnv.NewTestResellV2Client() + + ctx := context.Background() + allKeypairs, _, err := keypairs.List(ctx, testEnv.Client) + + if allKeypairs != nil { + t.Fatal("expected no keypairs from the List method") + } + if err == nil { + t.Fatal("expected error from the List method") + } +} + +func TestListKeypairsUnmarshalError(t *testing.T) { + endpointCalled := false + + testEnv := testutils.SetupTestEnv() + defer testEnv.TearDownTestEnv() + testEnv.NewTestResellV2Client() + testutils.HandleReqWithoutBody(t, &testutils.HandleReqOpts{ + Mux: testEnv.Mux, + URL: "/resell/v2/keypairs", + RawResponse: TestManyKeypairsInvalidResponseRaw, + Method: http.MethodGet, + Status: http.StatusOK, + CallFlag: &endpointCalled, + }) + + ctx := context.Background() + allKeypairs, _, err := keypairs.List(ctx, testEnv.Client) + + if !endpointCalled { + t.Fatal("endpoint wasn't called") + } + if allKeypairs != nil { + t.Fatal("expected no keypairs from the List method") + } + if err == nil { + t.Fatal("expected error from the List method") + } +}