Generate new version of SDK resources and Add Tests (#331)

This commit is contained in:
Todd Knight authored and GitHub committed 2020-09-08 16:27:51 -04:00
1 parent 96e4b1cdba
commit c3ecea172d
93 files changed
+3414 -2826

No files matched your search

+27 -25
View File
@@ -27,27 +27,42 @@ type Account struct {
Attributes map[string]interface{} `json:"attributes,omitempty"`
}
// Client is a client for this collection
type Client struct {
client *api.Client
}
// Creates a new client for this collection. The submitted API client is cloned;
// modifications to it after generating this client will not have effect. If you
// need to make changes to the underlying API client, use ApiClient() to access
// it.
func NewClient(c *api.Client) *Client {
return &Client{client: c}
return &Client{client: c.Clone()}
}
// ApiClient returns the underlying API client
func (c *Client) ApiClient() *api.Client {
return c.client
}
func (c *Client) Create(ctx context.Context, authMethodId string, opt ...Option) (*Account, *api.Error, error) {
if authMethodId == "" {
return nil, nil, fmt.Errorf("empty authMethodId value passed into Create request")
}
opts, apiOpts := getOpts(opt...)
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
req, err := c.client.NewRequest(ctx, "POST", fmt.Sprintf("auth-methods/%s/accounts", authMethodId), opts.postMap, apiOpts...)
opts.postMap["auth_method_id"] = authMethodId
req, err := c.client.NewRequest(ctx, "POST", "accounts", opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Create request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
@@ -72,22 +87,17 @@ func (c *Client) Create(ctx context.Context, authMethodId string, opt ...Option)
return target, apiErr, nil
}
func (c *Client) Read(ctx context.Context, authMethodId string, accountId string, opt ...Option) (*Account, *api.Error, error) {
if authMethodId == "" {
return nil, nil, fmt.Errorf("empty authMethodId value passed into Read request")
}
func (c *Client) Read(ctx context.Context, accountId string, opt ...Option) (*Account, *api.Error, error) {
if accountId == "" {
return nil, nil, fmt.Errorf("empty accountId value passed into Read request")
return nil, nil, fmt.Errorf("empty accountId value passed into Read request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
req, err := c.client.NewRequest(ctx, "GET", fmt.Sprintf("auth-methods/%s/accounts/%s", authMethodId, accountId), nil, apiOpts...)
req, err := c.client.NewRequest(ctx, "GET", fmt.Sprintf("accounts/%s", accountId), nil, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Read request: %w", err)
}
@@ -116,10 +126,7 @@ func (c *Client) Read(ctx context.Context, authMethodId string, accountId string
return target, apiErr, nil
}
func (c *Client) Update(ctx context.Context, authMethodId string, accountId string, version uint32, opt ...Option) (*Account, *api.Error, error) {
if authMethodId == "" {
return nil, nil, fmt.Errorf("empty authMethodId value passed into Update request")
}
func (c *Client) Update(ctx context.Context, accountId string, version uint32, opt ...Option) (*Account, *api.Error, error) {
if accountId == "" {
return nil, nil, fmt.Errorf("empty accountId value passed into Update request")
}
@@ -133,7 +140,7 @@ func (c *Client) Update(ctx context.Context, authMethodId string, accountId stri
if !opts.withAutomaticVersioning {
return nil, nil, errors.New("zero version number passed into Update request and automatic versioning not specified")
}
existingTarget, existingApiErr, existingErr := c.Read(ctx, authMethodId, accountId, opt...)
existingTarget, existingApiErr, existingErr := c.Read(ctx, accountId, opt...)
if existingErr != nil {
return nil, nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
}
@@ -148,7 +155,7 @@ func (c *Client) Update(ctx context.Context, authMethodId string, accountId stri
opts.postMap["version"] = version
req, err := c.client.NewRequest(ctx, "PATCH", fmt.Sprintf("auth-methods/%s/accounts/%s", authMethodId, accountId), opts.postMap, apiOpts...)
req, err := c.client.NewRequest(ctx, "PATCH", fmt.Sprintf("accounts/%s", accountId), opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Update request: %w", err)
}
@@ -177,22 +184,17 @@ func (c *Client) Update(ctx context.Context, authMethodId string, accountId stri
return target, apiErr, nil
}
func (c *Client) Delete(ctx context.Context, authMethodId string, accountId string, opt ...Option) (bool, *api.Error, error) {
if authMethodId == "" {
return false, nil, fmt.Errorf("empty authMethodId value passed into Delete request")
}
func (c *Client) Delete(ctx context.Context, accountId string, opt ...Option) (bool, *api.Error, error) {
if accountId == "" {
return false, nil, fmt.Errorf("empty accountId value passed into Delete request")
}
if c.client == nil {
return false, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
req, err := c.client.NewRequest(ctx, "DELETE", fmt.Sprintf("auth-methods/%s/accounts/%s", authMethodId, accountId), nil, apiOpts...)
req, err := c.client.NewRequest(ctx, "DELETE", fmt.Sprintf("accounts/%s", accountId), nil, apiOpts...)
if err != nil {
return false, nil, fmt.Errorf("error creating Delete request: %w", err)
}
@@ -228,14 +230,14 @@ func (c *Client) List(ctx context.Context, authMethodId string, opt ...Option) (
if authMethodId == "" {
return nil, nil, fmt.Errorf("empty authMethodId value passed into List request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
opts.queryMap["auth_method_id"] = authMethodId
req, err := c.client.NewRequest(ctx, "GET", fmt.Sprintf("auth-methods/%s/accounts", authMethodId), nil, apiOpts...)
req, err := c.client.NewRequest(ctx, "GET", "accounts", nil, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating List request: %w", err)
}
+35 -48
View File
@@ -3,6 +3,7 @@ package accounts_test
import (
"fmt"
"net/http"
"os"
"testing"
"github.com/hashicorp/boundary/api"
@@ -15,18 +16,21 @@ import (
"github.com/stretchr/testify/require"
)
func TestAccounts_List(t *testing.T) {
func TestList(t *testing.T) {
os.Setenv("BOUNDARY_LOG_URLS", "1")
os.Setenv("BOUNDARY_DEV_SKIP_AUTHZ", "1")
assert, require := assert.New(t), require.New(t)
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org := iam.TestOrg(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
require.NotNil(client)
token := tc.Token()
require.NotNil(token)
client.SetToken(token.Token)
org := iam.TestOrg(t, tc.IamRepo(), iam.WithUserId(token.UserId))
amClient := authmethods.NewClient(client)
am, apiErr, err := amClient.Create(tc.Context(), "password")
am, apiErr, err := amClient.Create(tc.Context(), "password", org.GetPublicId())
require.NoError(err)
require.Nil(apiErr)
require.NotNil(am)
@@ -77,21 +81,15 @@ func comparableSlice(in []*accounts.Account) []accounts.Account {
return filtered
}
func TestAccount_Crud(t *testing.T) {
func TestCrud(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org := iam.TestOrg(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
amId := token.AuthMethodId
accountClient := accounts.NewClient(client)
checkAccount := func(step string, u *accounts.Account, apiErr *api.Error, err error, wantedName string, wantedVersion uint32) {
@@ -111,35 +109,30 @@ func TestAccount_Crud(t *testing.T) {
u, apiErr, err := accountClient.Create(tc.Context(), amId, accounts.WithName("foo"), accounts.WithPasswordAccountLoginName("loginname"))
checkAccount("create", u, apiErr, err, "foo", 1)
u, apiErr, err = accountClient.Read(tc.Context(), amId, u.Id)
u, apiErr, err = accountClient.Read(tc.Context(), u.Id)
checkAccount("read", u, apiErr, err, "foo", 1)
u, apiErr, err = accountClient.Update(tc.Context(), amId, u.Id, u.Version, accounts.WithName("bar"))
u, apiErr, err = accountClient.Update(tc.Context(), u.Id, u.Version, accounts.WithName("bar"))
checkAccount("update", u, apiErr, err, "bar", 2)
u, apiErr, err = accountClient.Update(tc.Context(), amId, u.Id, u.Version, accounts.DefaultName())
u, apiErr, err = accountClient.Update(tc.Context(), u.Id, u.Version, accounts.DefaultName())
checkAccount("update", u, apiErr, err, "", 3)
existed, _, err := accountClient.Delete(tc.Context(), amId, u.Id)
existed, _, err := accountClient.Delete(tc.Context(), u.Id)
require.NoError(err)
assert.Nil(apiErr)
assert.True(existed, "Expected existing account when deleted, but it wasn't.")
}
func TestAccount_CustomMethods(t *testing.T) {
func TestCustomMethods(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org := iam.TestOrg(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
amId := token.AuthMethodId
accountClient := accounts.NewClient(client)
@@ -150,34 +143,28 @@ func TestAccount_CustomMethods(t *testing.T) {
acct := al[0]
setAcct, apiErr, err := accountClient.SetPassword(tc.Context(), amId, acct.Id, "setpassword", acct.Version)
setAcct, apiErr, err := accountClient.SetPassword(tc.Context(), acct.Id, "setpassword", acct.Version)
require.NoError(err)
require.Nil(apiErr)
require.NotNil(setAcct)
assert.Equal(acct.Version+1, setAcct.Version)
changeAcct, apiErr, err := accountClient.ChangePassword(tc.Context(), amId, acct.Id, "setpassword", "changepassword", setAcct.Version)
changeAcct, apiErr, err := accountClient.ChangePassword(tc.Context(), acct.Id, "setpassword", "changepassword", setAcct.Version)
require.NoError(err)
require.Nil(apiErr)
require.NotNil(changeAcct)
assert.Equal(setAcct.Version+1, changeAcct.Version)
}
func TestAccount_Errors(t *testing.T) {
func TestErrors(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org := iam.TestOrg(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
amId := token.AuthMethodId
accountClient := accounts.NewClient(client)
u, apiErr, err := accountClient.Create(tc.Context(), amId, accounts.WithPasswordAccountLoginName("first"))
@@ -190,17 +177,17 @@ func TestAccount_Errors(t *testing.T) {
require.NoError(err)
assert.NotNil(apiErr)
_, apiErr, err = accountClient.Read(tc.Context(), amId, password.AccountPrefix+"_doesntexis")
_, apiErr, err = accountClient.Read(tc.Context(), password.AccountPrefix+"_doesntexis")
require.NoError(err)
assert.NotNil(apiErr)
assert.EqualValues(http.StatusForbidden, apiErr.Status)
_, apiErr, err = accountClient.Read(tc.Context(), amId, "invalid id")
_, apiErr, err = accountClient.Read(tc.Context(), "invalid id")
require.NoError(err)
assert.NotNil(apiErr)
assert.EqualValues(http.StatusBadRequest, apiErr.Status)
_, apiErr, err = accountClient.Update(tc.Context(), amId, u.Id, u.Version)
_, apiErr, err = accountClient.Update(tc.Context(), u.Id, u.Version)
require.NoError(err)
assert.NotNil(apiErr)
assert.EqualValues(http.StatusBadRequest, apiErr.Status)
+6 -9
View File
@@ -9,10 +9,7 @@ import (
"github.com/kr/pretty"
)
func (c *Client) ChangePassword(ctx context.Context, authMethodId, accountId, oldPassword, newPassword string, version uint32, opt ...Option) (*Account, *api.Error, error) {
if authMethodId == "" {
return nil, nil, fmt.Errorf("empty authMethodId value passed into ChangePassword request")
}
func (c *Client) ChangePassword(ctx context.Context, accountId, currentPassword, newPassword string, version uint32, opt ...Option) (*Account, *api.Error, error) {
if accountId == "" {
return nil, nil, fmt.Errorf("empty accountId value passed into ChangePassword request")
}
@@ -26,7 +23,7 @@ func (c *Client) ChangePassword(ctx context.Context, authMethodId, accountId, ol
if !opts.withAutomaticVersioning {
return nil, nil, errors.New("zero version number passed into Update request and automatic versioning not specified")
}
existingTarget, existingApiErr, existingErr := c.Read(ctx, authMethodId, accountId, opt...)
existingTarget, existingApiErr, existingErr := c.Read(ctx, accountId, opt...)
if existingErr != nil {
return nil, nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
}
@@ -40,12 +37,12 @@ func (c *Client) ChangePassword(ctx context.Context, authMethodId, accountId, ol
}
reqBody := map[string]interface{}{
"version": version,
"old_password": oldPassword,
"new_password": newPassword,
"version": version,
"current_password": currentPassword,
"new_password": newPassword,
}
req, err := c.client.NewRequest(ctx, "POST", fmt.Sprintf("auth-methods/%s/accounts/%s:change-password", authMethodId, accountId), reqBody, apiOpts...)
req, err := c.client.NewRequest(ctx, "POST", fmt.Sprintf("accounts/%s:change-password", accountId), reqBody, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating ChangePassword request: %w", err)
}
+2 -12
View File
@@ -16,7 +16,6 @@ type Option func(*options)
type options struct {
postMap map[string]interface{}
queryMap map[string]string
withScopeId string
withAutomaticVersioning bool
}
@@ -33,25 +32,16 @@ func getOpts(opt ...Option) (options, []api.Option) {
o(&opts)
}
var apiOpts []api.Option
if opts.withScopeId != "" {
apiOpts = append(apiOpts, api.WithScopeId(opts.withScopeId))
}
return opts, apiOpts
}
func WithScopeId(id string) Option {
return func(o *options) {
o.withScopeId = id
}
}
// If set, and if the version is zero during an update, the API will perform a
// fetch to get the current version of the resource and populate it during the
// update call. This is convenient but opens up the possibility for subtle
// order-of-modification issues, so use carefully.
func WithAutomaticVersioning() Option {
func WithAutomaticVersioning(enable bool) Option {
return func(o *options) {
o.withAutomaticVersioning = true
o.withAutomaticVersioning = enable
}
}
+3 -6
View File
@@ -9,10 +9,7 @@ import (
"github.com/kr/pretty"
)
func (c *Client) SetPassword(ctx context.Context, authMethodId, accountId, password string, version uint32, opt ...Option) (*Account, *api.Error, error) {
if authMethodId == "" {
return nil, nil, fmt.Errorf("empty authMethodId value passed into SetPassword request")
}
func (c *Client) SetPassword(ctx context.Context, accountId, password string, version uint32, opt ...Option) (*Account, *api.Error, error) {
if accountId == "" {
return nil, nil, fmt.Errorf("empty accountId value passed into SetPassword request")
}
@@ -26,7 +23,7 @@ func (c *Client) SetPassword(ctx context.Context, authMethodId, accountId, passw
if !opts.withAutomaticVersioning {
return nil, nil, errors.New("zero version number passed into Update request and automatic versioning not specified")
}
existingTarget, existingApiErr, existingErr := c.Read(ctx, authMethodId, accountId, opt...)
existingTarget, existingApiErr, existingErr := c.Read(ctx, accountId, opt...)
if existingErr != nil {
return nil, nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
}
@@ -44,7 +41,7 @@ func (c *Client) SetPassword(ctx context.Context, authMethodId, accountId, passw
"password": password,
}
req, err := c.client.NewRequest(ctx, "POST", fmt.Sprintf("auth-methods/%s/accounts/%s:set-password", authMethodId, accountId), reqBody, apiOpts...)
req, err := c.client.NewRequest(ctx, "POST", fmt.Sprintf("accounts/%s:set-password", accountId), reqBody, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating SetPassword request: %w", err)
}
+2 -7
View File
@@ -8,9 +8,7 @@ import (
"github.com/hashicorp/boundary/api/authtokens"
)
// TODO: This will need to be changed when we add Auth Method API to boundary. We'll also need a better
// way to handle different auth method types.
func (c *Client) Authenticate(ctx context.Context, authMethodId, loginName, password string, opt ...Option) (*authtokens.AuthToken, *api.Error, error) {
func (c *Client) Authenticate(ctx context.Context, authMethodId string, credentials map[string]interface{}, opt ...Option) (*authtokens.AuthToken, *api.Error, error) {
if c.client == nil {
return nil, nil, fmt.Errorf("nil client in Authenticate request")
}
@@ -18,10 +16,7 @@ func (c *Client) Authenticate(ctx context.Context, authMethodId, loginName, pass
_, apiOpts := getOpts(opt...)
reqBody := map[string]interface{}{
"credentials": map[string]string{
"login_name": loginName,
"password": password,
},
"credentials": credentials,
}
req, err := c.client.NewRequest(ctx, "POST", fmt.Sprintf("auth-methods/%s:authenticate", authMethodId), reqBody, apiOpts...)
+5 -6
View File
@@ -15,22 +15,21 @@ func TestAuthenticate(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
defer tc.Shutdown()
client := tc.Client()
methods := authmethods.NewClient(client)
tok, apiErr, err := methods.Authenticate(tc.Context(), amId, "user", "passpass")
tok, apiErr, err := methods.Authenticate(tc.Context(), amId, map[string]interface{}{"login_name": "user", "password": "passpass"})
require.NoError(err)
assert.Nil(apiErr, pretty.Sprint(apiErr))
assert.NotNil(tok)
_, apiErr, err = methods.Authenticate(tc.Context(), amId, "user", "wrong")
_, apiErr, err = methods.Authenticate(tc.Context(), amId, map[string]interface{}{"login_name": "user", "password": "wrong"})
require.NoError(err)
require.NotNil(t, apiErr)
assert.EqualValuesf(http.StatusUnauthorized, apiErr.Status, "Expected unauthenticated, got %q", apiErr.Message)
+26 -6
View File
@@ -27,16 +27,31 @@ type AuthMethod struct {
Attributes map[string]interface{} `json:"attributes,omitempty"`
}
// Client is a client for this collection
type Client struct {
client *api.Client
}
// Creates a new client for this collection. The submitted API client is cloned;
// modifications to it after generating this client will not have effect. If you
// need to make changes to the underlying API client, use ApiClient() to access
// it.
func NewClient(c *api.Client) *Client {
return &Client{client: c}
return &Client{client: c.Clone()}
}
func (c *Client) Create(ctx context.Context, resourceType string, opt ...Option) (*AuthMethod, *api.Error, error) {
// ApiClient returns the underlying API client
func (c *Client) ApiClient() *api.Client {
return c.client
}
func (c *Client) Create(ctx context.Context, resourceType string, scopeId string, opt ...Option) (*AuthMethod, *api.Error, error) {
if scopeId == "" {
return nil, nil, fmt.Errorf("empty scopeId value passed into Create request")
}
opts, apiOpts := getOpts(opt...)
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
@@ -46,10 +61,13 @@ func (c *Client) Create(ctx context.Context, resourceType string, opt ...Option)
opts.postMap["type"] = resourceType
}
opts.postMap["scope_id"] = scopeId
req, err := c.client.NewRequest(ctx, "POST", "auth-methods", opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Create request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
@@ -76,9 +94,8 @@ func (c *Client) Create(ctx context.Context, resourceType string, opt ...Option)
func (c *Client) Read(ctx context.Context, authMethodId string, opt ...Option) (*AuthMethod, *api.Error, error) {
if authMethodId == "" {
return nil, nil, fmt.Errorf("empty authMethodId value passed into Read request")
return nil, nil, fmt.Errorf("empty authMethodId value passed into Read request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
@@ -176,7 +193,6 @@ func (c *Client) Delete(ctx context.Context, authMethodId string, opt ...Option)
if authMethodId == "" {
return false, nil, fmt.Errorf("empty authMethodId value passed into Delete request")
}
if c.client == nil {
return false, nil, fmt.Errorf("nil client")
}
@@ -215,12 +231,16 @@ func (c *Client) Delete(ctx context.Context, authMethodId string, opt ...Option)
return target.Existed, apiErr, nil
}
func (c *Client) List(ctx context.Context, opt ...Option) ([]*AuthMethod, *api.Error, error) {
func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*AuthMethod, *api.Error, error) {
if scopeId == "" {
return nil, nil, fmt.Errorf("empty scopeId value passed into List request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
opts.queryMap["scope_id"] = scopeId
req, err := c.client.NewRequest(ctx, "GET", "auth-methods", nil, apiOpts...)
if err != nil {
+2 -12
View File
@@ -16,7 +16,6 @@ type Option func(*options)
type options struct {
postMap map[string]interface{}
queryMap map[string]string
withScopeId string
withAutomaticVersioning bool
}
@@ -33,25 +32,16 @@ func getOpts(opt ...Option) (options, []api.Option) {
o(&opts)
}
var apiOpts []api.Option
if opts.withScopeId != "" {
apiOpts = append(apiOpts, api.WithScopeId(opts.withScopeId))
}
return opts, apiOpts
}
func WithScopeId(id string) Option {
return func(o *options) {
o.withScopeId = id
}
}
// If set, and if the version is zero during an update, the API will perform a
// fetch to get the current version of the resource and populate it during the
// update call. This is convenient but opens up the possibility for subtle
// order-of-modification issues, so use carefully.
func WithAutomaticVersioning() Option {
func WithAutomaticVersioning(enable bool) Option {
return func(o *options) {
o.withAutomaticVersioning = true
o.withAutomaticVersioning = enable
}
}
+44 -26
View File
@@ -8,6 +8,7 @@ import (
"github.com/hashicorp/boundary/api/accounts"
"github.com/hashicorp/boundary/api/authmethods"
"github.com/hashicorp/boundary/api/authtokens"
"github.com/hashicorp/boundary/api/roles"
"github.com/hashicorp/boundary/internal/authtoken"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/servers/controller"
@@ -15,21 +16,41 @@ import (
"github.com/stretchr/testify/require"
)
func TestAuthTokens_List(t *testing.T) {
func TestList(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
defer tc.Shutdown()
token := tc.Token()
client := tc.Client()
org := iam.TestOrg(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
client.SetToken(token.Token)
org := iam.TestOrg(t, tc.IamRepo(), iam.WithUserId(token.UserId))
amClient := authmethods.NewClient(client)
am, apiErr, err := amClient.Create(tc.Context(), "password")
am, apiErr, err := amClient.Create(tc.Context(), "password", org.GetPublicId())
require.NoError(err)
require.Nil(apiErr)
require.NotNil(am)
amId := am.Id
amId = am.Id
rolesClient := roles.NewClient(client)
role, apiErr, err := rolesClient.Create(tc.Context(), org.GetPublicId())
require.NoError(err)
require.Nil(apiErr)
require.NotNil(role)
role, apiErr, err = rolesClient.AddPrincipals(tc.Context(), role.Id, 0, []string{"u_anon"}, roles.WithAutomaticVersioning(true))
require.NoError(err)
require.Nil(apiErr)
require.NotNil(role)
role, apiErr, err = rolesClient.AddGrants(tc.Context(), role.Id, 0, []string{"type=auth-method;actions=authenticate"}, roles.WithAutomaticVersioning(true))
require.NoError(err)
require.Nil(apiErr)
require.NotNil(role)
acctClient := accounts.NewClient(client)
acct, apiErr, err := acctClient.Create(tc.Context(), amId, accounts.WithPasswordAccountLoginName("user"), accounts.WithPasswordAccountPassword("passpass"))
@@ -38,32 +59,32 @@ func TestAuthTokens_List(t *testing.T) {
require.NotNil(acct)
tokens := authtokens.NewClient(client)
methods := authmethods.NewClient(client)
atl, apiErr, err := tokens.List(tc.Context())
atl, apiErr, err := tokens.List(tc.Context(), org.GetPublicId())
require.NoError(err)
assert.Nil(apiErr)
assert.Empty(atl)
var expected []*authtokens.AuthToken
methods := authmethods.NewClient(client)
at, apiErr, err := methods.Authenticate(tc.Context(), amId, "user", "passpass")
at, apiErr, err := methods.Authenticate(tc.Context(), amId, map[string]interface{}{"login_name": "user", "password": "passpass"})
require.NoError(err)
assert.Nil(apiErr)
expected = append(expected, at)
atl, apiErr, err = tokens.List(tc.Context())
atl, apiErr, err = tokens.List(tc.Context(), org.GetPublicId())
require.NoError(err)
assert.Nil(apiErr)
assert.ElementsMatch(comparableSlice(expected), comparableSlice(atl))
for i := 1; i < 10; i++ {
at, apiErr, err = methods.Authenticate(tc.Context(), amId, "user", "passpass")
at, apiErr, err = methods.Authenticate(tc.Context(), amId, map[string]interface{}{"login_name": "user", "password": "passpass"})
require.NoError(err)
assert.Nil(apiErr)
expected = append(expected, at)
}
atl, apiErr, err = tokens.List(tc.Context())
atl, apiErr, err = tokens.List(tc.Context(), org.GetPublicId())
require.NoError(err)
assert.Nil(apiErr)
assert.ElementsMatch(comparableSlice(expected), comparableSlice(atl))
@@ -92,22 +113,23 @@ func comparableSlice(in []*authtokens.AuthToken) []authtokens.AuthToken {
return filtered
}
func TestAuthToken_Crud(t *testing.T) {
func TestCrud(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
defer tc.Shutdown()
client := tc.Client()
token := tc.Token()
client.SetToken(token.Token)
tokens := authtokens.NewClient(client)
methods := authmethods.NewClient(client)
want, apiErr, err := methods.Authenticate(tc.Context(), amId, "user", "passpass")
want, apiErr, err := methods.Authenticate(tc.Context(), amId, map[string]interface{}{"login_name": "user", "password": "passpass"})
require.NoError(err)
assert.Empty(apiErr)
@@ -122,18 +144,14 @@ func TestAuthToken_Crud(t *testing.T) {
assert.True(existed, "Expected existing token when deleted, but it wasn't.")
}
func TestAuthToken_Errors(t *testing.T) {
func TestErrors(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
token := tc.Token()
client.SetToken(token.Token)
tokens := authtokens.NewClient(client)
_, apiErr, err := tokens.Read(tc.Context(), authtoken.AuthTokenPrefix+"_doesntexis")
+17 -5
View File
@@ -24,19 +24,28 @@ type AuthToken struct {
ExpirationTime time.Time `json:"expiration_time,omitempty"`
}
// Client is a client for this collection
type Client struct {
client *api.Client
}
// Creates a new client for this collection. The submitted API client is cloned;
// modifications to it after generating this client will not have effect. If you
// need to make changes to the underlying API client, use ApiClient() to access
// it.
func NewClient(c *api.Client) *Client {
return &Client{client: c}
return &Client{client: c.Clone()}
}
// ApiClient returns the underlying API client
func (c *Client) ApiClient() *api.Client {
return c.client
}
func (c *Client) Read(ctx context.Context, authTokenId string, opt ...Option) (*AuthToken, *api.Error, error) {
if authTokenId == "" {
return nil, nil, fmt.Errorf("empty authTokenId value passed into Read request")
return nil, nil, fmt.Errorf("empty authTokenId value passed into Read request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
@@ -76,7 +85,6 @@ func (c *Client) Delete(ctx context.Context, authTokenId string, opt ...Option)
if authTokenId == "" {
return false, nil, fmt.Errorf("empty authTokenId value passed into Delete request")
}
if c.client == nil {
return false, nil, fmt.Errorf("nil client")
}
@@ -115,12 +123,16 @@ func (c *Client) Delete(ctx context.Context, authTokenId string, opt ...Option)
return target.Existed, apiErr, nil
}
func (c *Client) List(ctx context.Context, opt ...Option) ([]*AuthToken, *api.Error, error) {
func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*AuthToken, *api.Error, error) {
if scopeId == "" {
return nil, nil, fmt.Errorf("empty scopeId value passed into List request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
opts.queryMap["scope_id"] = scopeId
req, err := c.client.NewRequest(ctx, "GET", "auth-tokens", nil, apiOpts...)
if err != nil {
+2 -12
View File
@@ -16,7 +16,6 @@ type Option func(*options)
type options struct {
postMap map[string]interface{}
queryMap map[string]string
withScopeId string
withAutomaticVersioning bool
}
@@ -33,24 +32,15 @@ func getOpts(opt ...Option) (options, []api.Option) {
o(&opts)
}
var apiOpts []api.Option
if opts.withScopeId != "" {
apiOpts = append(apiOpts, api.WithScopeId(opts.withScopeId))
}
return opts, apiOpts
}
func WithScopeId(id string) Option {
return func(o *options) {
o.withScopeId = id
}
}
// If set, and if the version is zero during an update, the API will perform a
// fetch to get the current version of the resource and populate it during the
// update call. This is convenient but opens up the possibility for subtle
// order-of-modification issues, so use carefully.
func WithAutomaticVersioning() Option {
func WithAutomaticVersioning(enable bool) Option {
return func(o *options) {
o.withAutomaticVersioning = true
o.withAutomaticVersioning = enable
}
}
+8 -69
View File
@@ -38,7 +38,6 @@ const EnvBoundaryMaxRetries = "BOUNDARY_MAX_RETRIES"
const EnvBoundaryToken = "BOUNDARY_TOKEN"
const EnvBoundaryRateLimit = "BOUNDARY_RATE_LIMIT"
const EnvBoundarySRVLookup = "BOUNDARY_SRV_LOOKUP"
const EnvBoundaryScopeId = "BOUNDARY_SCOPE_ID"
// Config is used to configure the creation of the client
type Config struct {
@@ -97,9 +96,6 @@ type Config struct {
// SRVLookup enables the client to lookup the host through DNS SRV lookup
SRVLookup bool
// ScopeId is the ID of the scope to use if not overridden per-call
ScopeId string
}
// TLSConfig contains the parameters needed to configure TLS on the HTTP client
@@ -140,7 +136,6 @@ func DefaultConfig() (*Config, error) {
HttpClient: cleanhttp.DefaultPooledClient(),
Timeout: time.Second * 60,
TLSConfig: &TLSConfig{},
ScopeId: "global",
}
// We read the environment now; after DefaultClient returns we can override
@@ -215,10 +210,9 @@ func (c *Config) ConfigureTLS() error {
return nil
}
// setAddr parses a given string and looks for scope info, setting the
// actual address to the base. Note that if a very malformed URL is passed in,
// this may not return what one expects. For now this is on purpose to avoid
// requiring error handling.
// setAddr parses a given string, setting the actual address to the base. Note
// that if a very malformed URL is passed in, this may not return what one
// expects. For now this is on purpose to avoid requiring error handling.
//
// This also removes any trailing "/v1"; we'll use that in our commands so we
// don't require it from users.
@@ -229,11 +223,12 @@ func (c *Config) setAddr(addr string) error {
}
c.Addr = fmt.Sprintf("%s://%s", u.Scheme, u.Host)
// If there is a scopes segment, elide everything after it. Do this only for
// the last "scopes" segment in case it's part of the base path.
if lastIndex := strings.LastIndex(u.Path, "scopes"); lastIndex != -1 {
// If there is a v1 segment, elide everything after it. Do this only for
// the last v1 segment in case it's part of the base path.
if lastIndex := strings.LastIndex(u.Path, "v1"); lastIndex != -1 {
u.Path = u.Path[:lastIndex]
}
// Remove trailing or leading slashes
path := strings.Trim(u.Path, "/")
// Remove v1 in front or back (e.g. they could have
@@ -270,10 +265,6 @@ func (c *Config) ReadEnvironment() error {
c.Token = v
}
if v := os.Getenv(EnvBoundaryScopeId); v != "" {
c.ScopeId = v
}
if v := os.Getenv(EnvBoundaryMaxRetries); v != "" {
maxRetries, err := strconv.ParseUint(v, 10, 32)
if err != nil {
@@ -439,23 +430,6 @@ func (c *Client) SetAddr(addr string) error {
return c.config.setAddr(addr)
}
// ScopeId fetches the scope ID the client will use by default
func (c *Client) ScopeId() string {
c.modifyLock.RLock()
defer c.modifyLock.RUnlock()
return c.config.ScopeId
}
// Sets the scope ID to use when making calls. This will apply to all calls with
// this client unless overridden per request via WithScopeId.
func (c *Client) SetScopeId(scopeId string) {
c.modifyLock.Lock()
defer c.modifyLock.Unlock()
c.config.ScopeId = scopeId
}
// SetTLSConfig sets the TLS parameters to use and calls ConfigureTLS
func (c *Client) SetTLSConfig(conf *TLSConfig) error {
c.modifyLock.Lock()
@@ -564,7 +538,6 @@ func (c *Client) Clone() *Client {
CheckRetry: config.CheckRetry,
Limiter: config.Limiter,
SRVLookup: config.SRVLookup,
ScopeId: config.ScopeId,
}
if config.TLSConfig != nil {
newConfig.TLSConfig = new(TLSConfig)
@@ -632,7 +605,6 @@ func (c *Client) NewRequest(ctx context.Context, method, requestPath string, bod
c.modifyLock.RLock()
addr := c.config.Addr
scopeId := c.config.ScopeId
srvLookup := c.config.SRVLookup
token := c.config.Token
httpClient := c.config.HttpClient
@@ -677,46 +649,13 @@ func (c *Client) NewRequest(ctx context.Context, method, requestPath string, bod
}
}
opts := getOpts(opt...)
if opts.withScopeId != "" {
scopeId = opts.withScopeId
}
if scopeId == "" {
scopeId = "global"
}
var finalPath string
switch opts.withNewStyle {
case true:
// Do nothing. Eventually, remove the notion of a scoped client; calls
// to specific resources won't need it, and calls to collections can
// take care of it in the functions themselves as part of the api
// parameters.
finalPath = path.Join(u.Path, "/v1/", requestPath)
default:
scopedPath := strings.TrimPrefix(requestPath, "/")
switch requestPath {
case "scopes":
// This is a special case for creating or listing scopes; don't do
// anything
default:
// If their path already has 'scopes/' in it, use the given request path
// instead of building it from the client's scope information
if !strings.HasPrefix(scopedPath, "scopes/") {
scopedPath = path.Join("scopes", scopeId, scopedPath)
}
}
finalPath = path.Join(u.Path, "/v1", scopedPath)
}
req := &http.Request{
Method: method,
URL: &url.URL{
User: u.User,
Scheme: u.Scheme,
Host: host,
Path: finalPath,
Path: path.Join(u.Path, "/v1/", requestPath),
},
Host: u.Host,
}
+1 -1
View File
@@ -47,7 +47,7 @@ func TestConfigSetAddress(t *testing.T) {
},
{
"longer path project",
"http://127.0.0.1:9200/v1/scopes/orgid/auth-methods",
"http://127.0.0.1:9200/v1/auth-methods",
"http://127.0.0.1:9200",
"",
},
+26 -6
View File
@@ -27,24 +27,42 @@ type Group struct {
Members []*Member `json:"members,omitempty"`
}
// Client is a client for this collection
type Client struct {
client *api.Client
}
// Creates a new client for this collection. The submitted API client is cloned;
// modifications to it after generating this client will not have effect. If you
// need to make changes to the underlying API client, use ApiClient() to access
// it.
func NewClient(c *api.Client) *Client {
return &Client{client: c}
return &Client{client: c.Clone()}
}
func (c *Client) Create(ctx context.Context, opt ...Option) (*Group, *api.Error, error) {
// ApiClient returns the underlying API client
func (c *Client) ApiClient() *api.Client {
return c.client
}
func (c *Client) Create(ctx context.Context, scopeId string, opt ...Option) (*Group, *api.Error, error) {
if scopeId == "" {
return nil, nil, fmt.Errorf("empty scopeId value passed into Create request")
}
opts, apiOpts := getOpts(opt...)
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts.postMap["scope_id"] = scopeId
req, err := c.client.NewRequest(ctx, "POST", "groups", opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Create request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
@@ -71,9 +89,8 @@ func (c *Client) Create(ctx context.Context, opt ...Option) (*Group, *api.Error,
func (c *Client) Read(ctx context.Context, groupId string, opt ...Option) (*Group, *api.Error, error) {
if groupId == "" {
return nil, nil, fmt.Errorf("empty groupId value passed into Read request")
return nil, nil, fmt.Errorf("empty groupId value passed into Read request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
@@ -171,7 +188,6 @@ func (c *Client) Delete(ctx context.Context, groupId string, opt ...Option) (boo
if groupId == "" {
return false, nil, fmt.Errorf("empty groupId value passed into Delete request")
}
if c.client == nil {
return false, nil, fmt.Errorf("nil client")
}
@@ -210,12 +226,16 @@ func (c *Client) Delete(ctx context.Context, groupId string, opt ...Option) (boo
return target.Existed, apiErr, nil
}
func (c *Client) List(ctx context.Context, opt ...Option) ([]*Group, *api.Error, error) {
func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*Group, *api.Error, error) {
if scopeId == "" {
return nil, nil, fmt.Errorf("empty scopeId value passed into List request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
opts.queryMap["scope_id"] = scopeId
req, err := c.client.NewRequest(ctx, "GET", "groups", nil, apiOpts...)
if err != nil {
+44 -65
View File
@@ -14,52 +14,45 @@ import (
"github.com/stretchr/testify/require"
)
func TestGroup_List(t *testing.T) {
func TestList(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org, proj := iam.TestScopes(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
projClient := client.Clone()
projClient.SetScopeId(proj.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
org, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
cases := []struct {
name string
scopeClient *api.Client
name string
scopeId string
}{
{
name: "org",
scopeClient: client,
name: "org",
scopeId: org.GetPublicId(),
},
{
name: "proj",
scopeClient: projClient,
name: "proj",
scopeId: proj.GetPublicId(),
},
}
for _, tt := range cases {
t.Run(tt.name, func(t *testing.T) {
grps := groups.NewClient(tt.scopeClient)
pl, apiErr, err := grps.List(tc.Context())
grps := groups.NewClient(client)
pl, apiErr, err := grps.List(tc.Context(), tt.scopeId)
assert.NoError(err)
assert.Nil(apiErr)
assert.Empty(pl)
expected := make([]*groups.Group, 10)
for i := 0; i < 10; i++ {
expected[i], apiErr, err = grps.Create(tc.Context(), groups.WithName(fmt.Sprint(i)))
expected[i], apiErr, err = grps.Create(tc.Context(), tt.scopeId, groups.WithName(fmt.Sprint(i)))
require.NoError(err)
assert.Nil(apiErr)
}
pl, apiErr, err = grps.List(tc.Context())
pl, apiErr, err = grps.List(tc.Context(), tt.scopeId)
require.NoError(err)
assert.Nil(apiErr)
require.NotNil(pl)
@@ -84,22 +77,15 @@ func comparableSlice(in []*groups.Group) []groups.Group {
return filtered
}
func TestGroup_Crud(t *testing.T) {
func TestCrud(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org, proj := iam.TestScopes(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
projClient := client.Clone()
projClient.SetScopeId(proj.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
org, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
checkGroup := func(step string, g *groups.Group, apiErr *api.Error, err error, wantedName string, wantedVersion uint32, expectedUserIds []string) {
require.NoError(err, step)
@@ -120,31 +106,31 @@ func TestGroup_Crud(t *testing.T) {
}
cases := []struct {
name string
scopeClient *api.Client
name string
scopeId string
}{
{
name: "org",
scopeClient: client,
name: "org",
scopeId: org.GetPublicId(),
},
{
name: "proj",
scopeClient: projClient,
name: "proj",
scopeId: proj.GetPublicId(),
},
}
user1, apiErr, err := users.NewClient(client).Create(tc.Context())
user1, apiErr, err := users.NewClient(client).Create(tc.Context(), org.GetPublicId())
require.NoError(err)
require.Nil(apiErr)
user2, apiErr, err := users.NewClient(client).Create(tc.Context())
user2, apiErr, err := users.NewClient(client).Create(tc.Context(), org.GetPublicId())
require.NoError(err)
require.Nil(apiErr)
for _, tt := range cases {
t.Run(tt.name, func(t *testing.T) {
groupsClient := groups.NewClient(tt.scopeClient)
g, apiErr, err := groupsClient.Create(tc.Context(), groups.WithName("foo"))
groupsClient := groups.NewClient(client)
g, apiErr, err := groupsClient.Create(tc.Context(), tt.scopeId, groups.WithName("foo"))
checkGroup("create", g, apiErr, err, "foo", 1, nil)
g, apiErr, err = groupsClient.Read(tc.Context(), g.Id)
@@ -177,48 +163,41 @@ func TestGroup_Crud(t *testing.T) {
}
}
func TestGroup_Errors(t *testing.T) {
func TestErrors(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org, proj := iam.TestScopes(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
projClient := client.Clone()
projClient.SetScopeId(proj.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
org, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
cases := []struct {
name string
scopeClient *api.Client
name string
scopeId string
}{
{
name: "org",
scopeClient: client,
name: "org",
scopeId: org.GetPublicId(),
},
{
name: "proj",
scopeClient: projClient,
name: "proj",
scopeId: proj.GetPublicId(),
},
}
for _, tt := range cases {
t.Run(tt.name, func(t *testing.T) {
groupClient := groups.NewClient(tt.scopeClient)
groupClient := groups.NewClient(client)
g, apiErr, err := groupClient.Create(tc.Context(), groups.WithName("first"))
g, apiErr, err := groupClient.Create(tc.Context(), tt.scopeId, groups.WithName("first"))
require.NoError(err)
assert.Nil(apiErr)
assert.NotNil(g)
// Create another resource with the same name.
_, apiErr, err = groupClient.Create(tc.Context(), groups.WithName("first"))
_, apiErr, err = groupClient.Create(tc.Context(), tt.scopeId, groups.WithName("first"))
require.NoError(err)
assert.NotNil(apiErr)
+2 -12
View File
@@ -16,7 +16,6 @@ type Option func(*options)
type options struct {
postMap map[string]interface{}
queryMap map[string]string
withScopeId string
withAutomaticVersioning bool
}
@@ -33,25 +32,16 @@ func getOpts(opt ...Option) (options, []api.Option) {
o(&opts)
}
var apiOpts []api.Option
if opts.withScopeId != "" {
apiOpts = append(apiOpts, api.WithScopeId(opts.withScopeId))
}
return opts, apiOpts
}
func WithScopeId(id string) Option {
return func(o *options) {
o.withScopeId = id
}
}
// If set, and if the version is zero during an update, the API will perform a
// fetch to get the current version of the resource and populate it during the
// update call. This is convenient but opens up the possibility for subtle
// order-of-modification issues, so use carefully.
func WithAutomaticVersioning() Option {
func WithAutomaticVersioning(enable bool) Option {
return func(o *options) {
o.withAutomaticVersioning = true
o.withAutomaticVersioning = enable
}
}
+26 -6
View File
@@ -27,16 +27,31 @@ type HostCatalog struct {
Attributes map[string]interface{} `json:"attributes,omitempty"`
}
// Client is a client for this collection
type Client struct {
client *api.Client
}
// Creates a new client for this collection. The submitted API client is cloned;
// modifications to it after generating this client will not have effect. If you
// need to make changes to the underlying API client, use ApiClient() to access
// it.
func NewClient(c *api.Client) *Client {
return &Client{client: c}
return &Client{client: c.Clone()}
}
func (c *Client) Create(ctx context.Context, resourceType string, opt ...Option) (*HostCatalog, *api.Error, error) {
// ApiClient returns the underlying API client
func (c *Client) ApiClient() *api.Client {
return c.client
}
func (c *Client) Create(ctx context.Context, resourceType string, scopeId string, opt ...Option) (*HostCatalog, *api.Error, error) {
if scopeId == "" {
return nil, nil, fmt.Errorf("empty scopeId value passed into Create request")
}
opts, apiOpts := getOpts(opt...)
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
@@ -46,10 +61,13 @@ func (c *Client) Create(ctx context.Context, resourceType string, opt ...Option)
opts.postMap["type"] = resourceType
}
opts.postMap["scope_id"] = scopeId
req, err := c.client.NewRequest(ctx, "POST", "host-catalogs", opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Create request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
@@ -76,9 +94,8 @@ func (c *Client) Create(ctx context.Context, resourceType string, opt ...Option)
func (c *Client) Read(ctx context.Context, hostCatalogId string, opt ...Option) (*HostCatalog, *api.Error, error) {
if hostCatalogId == "" {
return nil, nil, fmt.Errorf("empty hostCatalogId value passed into Read request")
return nil, nil, fmt.Errorf("empty hostCatalogId value passed into Read request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
@@ -176,7 +193,6 @@ func (c *Client) Delete(ctx context.Context, hostCatalogId string, opt ...Option
if hostCatalogId == "" {
return false, nil, fmt.Errorf("empty hostCatalogId value passed into Delete request")
}
if c.client == nil {
return false, nil, fmt.Errorf("nil client")
}
@@ -215,12 +231,16 @@ func (c *Client) Delete(ctx context.Context, hostCatalogId string, opt ...Option
return target.Existed, apiErr, nil
}
func (c *Client) List(ctx context.Context, opt ...Option) ([]*HostCatalog, *api.Error, error) {
func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*HostCatalog, *api.Error, error) {
if scopeId == "" {
return nil, nil, fmt.Errorf("empty scopeId value passed into List request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
opts.queryMap["scope_id"] = scopeId
req, err := c.client.NewRequest(ctx, "GET", "host-catalogs", nil, apiOpts...)
if err != nil {
+24 -41
View File
@@ -14,23 +14,18 @@ import (
"github.com/stretchr/testify/require"
)
func TestCatalog_List(t *testing.T) {
func TestList(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
_, proj := iam.TestScopes(t, tc.IamRepo())
client.SetScopeId(proj.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
catalogClient := hostcatalogs.NewClient(client)
ul, apiErr, err := catalogClient.List(tc.Context())
ul, apiErr, err := catalogClient.List(tc.Context(), proj.GetPublicId())
assert.NoError(err)
assert.Nil(apiErr)
assert.Empty(ul)
@@ -40,21 +35,21 @@ func TestCatalog_List(t *testing.T) {
expected = append(expected, &hostcatalogs.HostCatalog{Name: fmt.Sprint(i)})
}
expected[0], apiErr, err = catalogClient.Create(tc.Context(), "static", hostcatalogs.WithName(expected[0].Name))
expected[0], apiErr, err = catalogClient.Create(tc.Context(), "static", proj.GetPublicId(), hostcatalogs.WithName(expected[0].Name))
assert.NoError(err)
assert.Nil(apiErr)
ul, apiErr, err = catalogClient.List(tc.Context())
ul, apiErr, err = catalogClient.List(tc.Context(), proj.GetPublicId())
assert.NoError(err)
assert.Nil(apiErr)
assert.ElementsMatch(comparableCatalogSlice(expected[:1]), comparableCatalogSlice(ul))
for i := 1; i < 10; i++ {
expected[i], apiErr, err = catalogClient.Create(tc.Context(), "static", hostcatalogs.WithName(expected[i].Name))
expected[i], apiErr, err = catalogClient.Create(tc.Context(), "static", proj.GetPublicId(), hostcatalogs.WithName(expected[i].Name))
assert.NoError(err)
assert.Nil(apiErr)
}
ul, apiErr, err = catalogClient.List(tc.Context())
ul, apiErr, err = catalogClient.List(tc.Context(), proj.GetPublicId())
require.NoError(err)
assert.Nil(apiErr)
assert.ElementsMatch(comparableCatalogSlice(expected), comparableCatalogSlice(ul))
@@ -75,22 +70,15 @@ func comparableCatalogSlice(in []*hostcatalogs.HostCatalog) []hostcatalogs.HostC
return filtered
}
func TestCatalogs_Crud(t *testing.T) {
func TestCrud(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org, proj := iam.TestScopes(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
projClient := client.Clone()
projClient.SetScopeId(proj.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
checkCatalog := func(step string, hc *hostcatalogs.HostCatalog, apiErr *api.Error, err error, wantedName string, wantVersion uint32) {
require.NoError(err, step)
@@ -106,9 +94,9 @@ func TestCatalogs_Crud(t *testing.T) {
assert.Equal(wantVersion, hc.Version)
}
hcClient := hostcatalogs.NewClient(projClient)
hcClient := hostcatalogs.NewClient(client)
hc, apiErr, err := hcClient.Create(tc.Context(), "static", hostcatalogs.WithName("foo"))
hc, apiErr, err := hcClient.Create(tc.Context(), "static", proj.GetPublicId(), hostcatalogs.WithName("foo"))
checkCatalog("create", hc, apiErr, err, "foo", 1)
hc, apiErr, err = hcClient.Read(tc.Context(), hc.Id)
@@ -131,28 +119,23 @@ func TestCatalogs_Crud(t *testing.T) {
}
// TODO: Get better coverage for expected errors and error formats.
func TestCatalogs_Errors(t *testing.T) {
func TestErrors(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
_, proj := iam.TestScopes(t, tc.IamRepo())
client.SetScopeId(proj.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
pc := hostcatalogs.NewClient(client)
hc, apiErr, err := pc.Create(tc.Context(), "static", hostcatalogs.WithName("foo"))
hc, apiErr, err := pc.Create(tc.Context(), "static", proj.GetPublicId(), hostcatalogs.WithName("foo"))
require.NoError(err)
assert.Nil(apiErr)
assert.NotNil(hc)
_, apiErr, err = pc.Create(tc.Context(), "static", hostcatalogs.WithName("foo"))
_, apiErr, err = pc.Create(tc.Context(), "static", proj.GetPublicId(), hostcatalogs.WithName("foo"))
require.NoError(err)
assert.NotNil(apiErr)
+2 -12
View File
@@ -16,7 +16,6 @@ type Option func(*options)
type options struct {
postMap map[string]interface{}
queryMap map[string]string
withScopeId string
withAutomaticVersioning bool
}
@@ -33,25 +32,16 @@ func getOpts(opt ...Option) (options, []api.Option) {
o(&opts)
}
var apiOpts []api.Option
if opts.withScopeId != "" {
apiOpts = append(apiOpts, api.WithScopeId(opts.withScopeId))
}
return opts, apiOpts
}
func WithScopeId(id string) Option {
return func(o *options) {
o.withScopeId = id
}
}
// If set, and if the version is zero during an update, the API will perform a
// fetch to get the current version of the resource and populate it during the
// update call. This is convenient but opens up the possibility for subtle
// order-of-modification issues, so use carefully.
func WithAutomaticVersioning() Option {
func WithAutomaticVersioning(enable bool) Option {
return func(o *options) {
o.withAutomaticVersioning = true
o.withAutomaticVersioning = enable
}
}
+27 -25
View File
@@ -28,27 +28,42 @@ type Host struct {
Attributes map[string]interface{} `json:"attributes,omitempty"`
}
// Client is a client for this collection
type Client struct {
client *api.Client
}
// Creates a new client for this collection. The submitted API client is cloned;
// modifications to it after generating this client will not have effect. If you
// need to make changes to the underlying API client, use ApiClient() to access
// it.
func NewClient(c *api.Client) *Client {
return &Client{client: c}
return &Client{client: c.Clone()}
}
// ApiClient returns the underlying API client
func (c *Client) ApiClient() *api.Client {
return c.client
}
func (c *Client) Create(ctx context.Context, hostCatalogId string, opt ...Option) (*Host, *api.Error, error) {
if hostCatalogId == "" {
return nil, nil, fmt.Errorf("empty hostCatalogId value passed into Create request")
}
opts, apiOpts := getOpts(opt...)
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
req, err := c.client.NewRequest(ctx, "POST", fmt.Sprintf("host-catalogs/%s/hosts", hostCatalogId), opts.postMap, apiOpts...)
opts.postMap["host_catalog_id"] = hostCatalogId
req, err := c.client.NewRequest(ctx, "POST", "hosts", opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Create request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
@@ -73,22 +88,17 @@ func (c *Client) Create(ctx context.Context, hostCatalogId string, opt ...Option
return target, apiErr, nil
}
func (c *Client) Read(ctx context.Context, hostCatalogId string, hostId string, opt ...Option) (*Host, *api.Error, error) {
if hostCatalogId == "" {
return nil, nil, fmt.Errorf("empty hostCatalogId value passed into Read request")
}
func (c *Client) Read(ctx context.Context, hostId string, opt ...Option) (*Host, *api.Error, error) {
if hostId == "" {
return nil, nil, fmt.Errorf("empty hostId value passed into Read request")
return nil, nil, fmt.Errorf("empty hostId value passed into Read request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
req, err := c.client.NewRequest(ctx, "GET", fmt.Sprintf("host-catalogs/%s/hosts/%s", hostCatalogId, hostId), nil, apiOpts...)
req, err := c.client.NewRequest(ctx, "GET", fmt.Sprintf("hosts/%s", hostId), nil, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Read request: %w", err)
}
@@ -117,10 +127,7 @@ func (c *Client) Read(ctx context.Context, hostCatalogId string, hostId string,
return target, apiErr, nil
}
func (c *Client) Update(ctx context.Context, hostCatalogId string, hostId string, version uint32, opt ...Option) (*Host, *api.Error, error) {
if hostCatalogId == "" {
return nil, nil, fmt.Errorf("empty hostCatalogId value passed into Update request")
}
func (c *Client) Update(ctx context.Context, hostId string, version uint32, opt ...Option) (*Host, *api.Error, error) {
if hostId == "" {
return nil, nil, fmt.Errorf("empty hostId value passed into Update request")
}
@@ -134,7 +141,7 @@ func (c *Client) Update(ctx context.Context, hostCatalogId string, hostId string
if !opts.withAutomaticVersioning {
return nil, nil, errors.New("zero version number passed into Update request and automatic versioning not specified")
}
existingTarget, existingApiErr, existingErr := c.Read(ctx, hostCatalogId, hostId, opt...)
existingTarget, existingApiErr, existingErr := c.Read(ctx, hostId, opt...)
if existingErr != nil {
return nil, nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
}
@@ -149,7 +156,7 @@ func (c *Client) Update(ctx context.Context, hostCatalogId string, hostId string
opts.postMap["version"] = version
req, err := c.client.NewRequest(ctx, "PATCH", fmt.Sprintf("host-catalogs/%s/hosts/%s", hostCatalogId, hostId), opts.postMap, apiOpts...)
req, err := c.client.NewRequest(ctx, "PATCH", fmt.Sprintf("hosts/%s", hostId), opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Update request: %w", err)
}
@@ -178,22 +185,17 @@ func (c *Client) Update(ctx context.Context, hostCatalogId string, hostId string
return target, apiErr, nil
}
func (c *Client) Delete(ctx context.Context, hostCatalogId string, hostId string, opt ...Option) (bool, *api.Error, error) {
if hostCatalogId == "" {
return false, nil, fmt.Errorf("empty hostCatalogId value passed into Delete request")
}
func (c *Client) Delete(ctx context.Context, hostId string, opt ...Option) (bool, *api.Error, error) {
if hostId == "" {
return false, nil, fmt.Errorf("empty hostId value passed into Delete request")
}
if c.client == nil {
return false, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
req, err := c.client.NewRequest(ctx, "DELETE", fmt.Sprintf("host-catalogs/%s/hosts/%s", hostCatalogId, hostId), nil, apiOpts...)
req, err := c.client.NewRequest(ctx, "DELETE", fmt.Sprintf("hosts/%s", hostId), nil, apiOpts...)
if err != nil {
return false, nil, fmt.Errorf("error creating Delete request: %w", err)
}
@@ -229,14 +231,14 @@ func (c *Client) List(ctx context.Context, hostCatalogId string, opt ...Option)
if hostCatalogId == "" {
return nil, nil, fmt.Errorf("empty hostCatalogId value passed into List request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
opts.queryMap["host_catalog_id"] = hostCatalogId
req, err := c.client.NewRequest(ctx, "GET", fmt.Sprintf("host-catalogs/%s/hosts", hostCatalogId), nil, apiOpts...)
req, err := c.client.NewRequest(ctx, "GET", "hosts", nil, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating List request: %w", err)
}
+26 -43
View File
@@ -15,22 +15,17 @@ import (
"github.com/stretchr/testify/require"
)
func TestHost_List(t *testing.T) {
func TestList(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
_, proj := iam.TestScopes(t, tc.IamRepo())
client.SetScopeId(proj.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
hc, apiErr, err := hostcatalogs.NewClient(client).Create(tc.Context(), "static")
hc, apiErr, err := hostcatalogs.NewClient(client).Create(tc.Context(), "static", proj.GetPublicId())
require.NoError(err)
require.Nil(apiErr)
require.NotNil(hc)
@@ -82,24 +77,17 @@ func comparableHostSlice(in []*hosts.Host) []hosts.Host {
return filtered
}
func TestHost_Crud(t *testing.T) {
func TestCrud(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org, proj := iam.TestScopes(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
projClient := client.Clone()
projClient.SetScopeId(proj.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
hc, apiErr, err := hostcatalogs.NewClient(projClient).Create(tc.Context(), "static")
hc, apiErr, err := hostcatalogs.NewClient(client).Create(tc.Context(), "static", proj.GetPublicId())
require.NoError(err)
require.Nil(apiErr)
require.NotNil(hc)
@@ -118,47 +106,42 @@ func TestHost_Crud(t *testing.T) {
assert.Equal(wantVersion, h.Version)
}
hClient := hosts.NewClient(projClient)
hClient := hosts.NewClient(client)
h, apiErr, err := hClient.Create(tc.Context(), hc.Id, hosts.WithName("foo"), hosts.WithStaticHostAddress("someaddress"))
checkHost("create", h, apiErr, err, "foo", 1)
h, apiErr, err = hClient.Read(tc.Context(), hc.Id, h.Id)
h, apiErr, err = hClient.Read(tc.Context(), h.Id)
checkHost("read", h, apiErr, err, "foo", 1)
h, apiErr, err = hClient.Update(tc.Context(), hc.Id, h.Id, h.Version, hosts.WithName("bar"))
h, apiErr, err = hClient.Update(tc.Context(), h.Id, h.Version, hosts.WithName("bar"))
checkHost("update", h, apiErr, err, "bar", 2)
h, apiErr, err = hClient.Update(tc.Context(), hc.Id, h.Id, h.Version, hosts.DefaultName())
h, apiErr, err = hClient.Update(tc.Context(), h.Id, h.Version, hosts.DefaultName())
checkHost("update", h, apiErr, err, "", 3)
existed, apiErr, err := hClient.Delete(tc.Context(), hc.Id, h.Id)
existed, apiErr, err := hClient.Delete(tc.Context(), h.Id)
assert.NoError(err)
assert.True(existed, "Expected existing catalog when deleted, but it wasn't.")
existed, apiErr, err = hClient.Delete(tc.Context(), hc.Id, h.Id)
existed, apiErr, err = hClient.Delete(tc.Context(), h.Id)
require.NoError(err)
assert.NotNil(apiErr)
assert.EqualValues(http.StatusForbidden, apiErr.Status)
}
// TODO: Get better coverage for expected errors and error formats.
func TestHost_Errors(t *testing.T) {
func TestErrors(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
_, proj := iam.TestScopes(t, tc.IamRepo())
client.SetScopeId(proj.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
hc, apiErr, err := hostcatalogs.NewClient(client).Create(tc.Context(), "static")
hc, apiErr, err := hostcatalogs.NewClient(client).Create(tc.Context(), "static", proj.GetPublicId())
require.NoError(err)
require.Nil(apiErr)
require.NotNil(hc)
@@ -174,12 +157,12 @@ func TestHost_Errors(t *testing.T) {
require.NoError(err)
assert.NotNil(apiErr)
_, apiErr, err = hClient.Read(tc.Context(), hc.Id, static.HostPrefix+"_doesntexis")
_, apiErr, err = hClient.Read(tc.Context(), static.HostPrefix+"_doesntexis")
require.NoError(err)
assert.NotNil(apiErr)
assert.EqualValues(apiErr.Status, http.StatusForbidden)
_, apiErr, err = hClient.Read(tc.Context(), hc.Id, "invalid id")
_, apiErr, err = hClient.Read(tc.Context(), "invalid id")
require.NoError(err)
assert.NotNil(apiErr)
assert.EqualValues(http.StatusBadRequest, apiErr.Status)
+2 -12
View File
@@ -16,7 +16,6 @@ type Option func(*options)
type options struct {
postMap map[string]interface{}
queryMap map[string]string
withScopeId string
withAutomaticVersioning bool
}
@@ -33,25 +32,16 @@ func getOpts(opt ...Option) (options, []api.Option) {
o(&opts)
}
var apiOpts []api.Option
if opts.withScopeId != "" {
apiOpts = append(apiOpts, api.WithScopeId(opts.withScopeId))
}
return opts, apiOpts
}
func WithScopeId(id string) Option {
return func(o *options) {
o.withScopeId = id
}
}
// If set, and if the version is zero during an update, the API will perform a
// fetch to get the current version of the resource and populate it during the
// update call. This is convenient but opens up the possibility for subtle
// order-of-modification issues, so use carefully.
func WithAutomaticVersioning() Option {
func WithAutomaticVersioning(enable bool) Option {
return func(o *options) {
o.withAutomaticVersioning = true
o.withAutomaticVersioning = enable
}
}
+22 -448
View File
@@ -28,252 +28,31 @@ type HostSet struct {
Attributes map[string]interface{} `json:"attributes,omitempty"`
}
// Client is a client for this collection
type Client struct {
client *api.Client
}
// Creates a new client for this collection. The submitted API client is cloned;
// modifications to it after generating this client will not have effect. If you
// need to make changes to the underlying API client, use ApiClient() to access
// it.
func NewClient(c *api.Client) *Client {
return &Client{client: c}
return &Client{client: c.Clone()}
}
// ApiClient returns the underlying API client
func (c *Client) ApiClient() *api.Client {
return c.client
}
func (c *Client) Create(ctx context.Context, hostCatalogId string, opt ...Option) (*HostSet, *api.Error, error) {
if hostCatalogId == "" {
return nil, nil, fmt.Errorf("empty hostCatalogId value passed into Create request")
}
opts, apiOpts := getOpts(opt...)
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
req, err := c.client.NewRequest(ctx, "POST", fmt.Sprintf("host-catalogs/%s/host-sets", hostCatalogId), opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Create request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
q.Add(k, v)
}
req.URL.RawQuery = q.Encode()
}
resp, err := c.client.Do(req)
if err != nil {
return nil, nil, fmt.Errorf("error performing client request during Create call: %w", err)
}
target := new(HostSet)
apiErr, err := resp.Decode(target)
if err != nil {
return nil, nil, fmt.Errorf("error decoding Create response: %w", err)
}
if apiErr != nil {
return nil, apiErr, nil
}
return target, apiErr, nil
}
func (c *Client) Read(ctx context.Context, hostCatalogId string, hostSetId string, opt ...Option) (*HostSet, *api.Error, error) {
if hostCatalogId == "" {
return nil, nil, fmt.Errorf("empty hostCatalogId value passed into Read request")
}
if hostSetId == "" {
return nil, nil, fmt.Errorf("empty hostSetId value passed into Read request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
req, err := c.client.NewRequest(ctx, "GET", fmt.Sprintf("host-catalogs/%s/host-sets/%s", hostCatalogId, hostSetId), nil, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Read request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
q.Add(k, v)
}
req.URL.RawQuery = q.Encode()
}
resp, err := c.client.Do(req)
if err != nil {
return nil, nil, fmt.Errorf("error performing client request during Read call: %w", err)
}
target := new(HostSet)
apiErr, err := resp.Decode(target)
if err != nil {
return nil, nil, fmt.Errorf("error decoding Read response: %w", err)
}
if apiErr != nil {
return nil, apiErr, nil
}
return target, apiErr, nil
}
func (c *Client) Update(ctx context.Context, hostCatalogId string, hostSetId string, version uint32, opt ...Option) (*HostSet, *api.Error, error) {
if hostCatalogId == "" {
return nil, nil, fmt.Errorf("empty hostCatalogId value passed into Update request")
}
if hostSetId == "" {
return nil, nil, fmt.Errorf("empty hostSetId value passed into Update request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
if version == 0 {
if !opts.withAutomaticVersioning {
return nil, nil, errors.New("zero version number passed into Update request and automatic versioning not specified")
}
existingTarget, existingApiErr, existingErr := c.Read(ctx, hostCatalogId, hostSetId, opt...)
if existingErr != nil {
return nil, nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
}
if existingApiErr != nil {
return nil, nil, fmt.Errorf("error from controller when performing initial check-and-set read: %s", pretty.Sprint(existingApiErr))
}
if existingTarget == nil {
return nil, nil, errors.New("nil resource found when performing initial check-and-set read")
}
version = existingTarget.Version
}
opts.postMap["version"] = version
req, err := c.client.NewRequest(ctx, "PATCH", fmt.Sprintf("host-catalogs/%s/host-sets/%s", hostCatalogId, hostSetId), opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Update request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
q.Add(k, v)
}
req.URL.RawQuery = q.Encode()
}
resp, err := c.client.Do(req)
if err != nil {
return nil, nil, fmt.Errorf("error performing client request during Update call: %w", err)
}
target := new(HostSet)
apiErr, err := resp.Decode(target)
if err != nil {
return nil, nil, fmt.Errorf("error decoding Update response: %w", err)
}
if apiErr != nil {
return nil, apiErr, nil
}
return target, apiErr, nil
}
func (c *Client) Delete(ctx context.Context, hostCatalogId string, hostSetId string, opt ...Option) (bool, *api.Error, error) {
if hostCatalogId == "" {
return false, nil, fmt.Errorf("empty hostCatalogId value passed into Delete request")
}
if hostSetId == "" {
return false, nil, fmt.Errorf("empty hostSetId value passed into Delete request")
}
if c.client == nil {
return false, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
req, err := c.client.NewRequest(ctx, "DELETE", fmt.Sprintf("host-catalogs/%s/host-sets/%s", hostCatalogId, hostSetId), nil, apiOpts...)
if err != nil {
return false, nil, fmt.Errorf("error creating Delete request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
q.Add(k, v)
}
req.URL.RawQuery = q.Encode()
}
resp, err := c.client.Do(req)
if err != nil {
return false, nil, fmt.Errorf("error performing client request during Delete call: %w", err)
}
type deleteResponse struct {
Existed bool
}
target := &deleteResponse{}
apiErr, err := resp.Decode(target)
if err != nil {
return false, nil, fmt.Errorf("error decoding Delete response: %w", err)
}
if apiErr != nil {
return false, apiErr, nil
}
return target.Existed, apiErr, nil
}
func (c *Client) List(ctx context.Context, hostCatalogId string, opt ...Option) ([]*HostSet, *api.Error, error) {
if hostCatalogId == "" {
return nil, nil, fmt.Errorf("empty hostCatalogId value passed into List request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
req, err := c.client.NewRequest(ctx, "GET", fmt.Sprintf("host-catalogs/%s/host-sets", hostCatalogId), nil, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating List request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
q.Add(k, v)
}
req.URL.RawQuery = q.Encode()
}
resp, err := c.client.Do(req)
if err != nil {
return nil, nil, fmt.Errorf("error performing client request during List call: %w", err)
}
type listResponse struct {
Items []*HostSet
}
target := &listResponse{}
apiErr, err := resp.Decode(target)
if err != nil {
return nil, nil, fmt.Errorf("error decoding List response: %w", err)
}
if apiErr != nil {
return nil, apiErr, nil
}
return target.Items, apiErr, nil
}
func (c *Client) Create2(ctx context.Context, hostCatalogId string, opt ...Option) (*HostSet, *api.Error, error) {
if hostCatalogId == "" {
return nil, nil, fmt.Errorf("empty hostCatalogId value passed into Create request")
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
@@ -309,7 +88,7 @@ func (c *Client) Create2(ctx context.Context, hostCatalogId string, opt ...Optio
return target, apiErr, nil
}
func (c *Client) Read2(ctx context.Context, hostSetId string, opt ...Option) (*HostSet, *api.Error, error) {
func (c *Client) Read(ctx context.Context, hostSetId string, opt ...Option) (*HostSet, *api.Error, error) {
if hostSetId == "" {
return nil, nil, fmt.Errorf("empty hostSetId value passed into Read request")
}
@@ -318,7 +97,6 @@ func (c *Client) Read2(ctx context.Context, hostSetId string, opt ...Option) (*H
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
req, err := c.client.NewRequest(ctx, "GET", fmt.Sprintf("host-sets/%s", hostSetId), nil, apiOpts...)
if err != nil {
@@ -349,7 +127,7 @@ func (c *Client) Read2(ctx context.Context, hostSetId string, opt ...Option) (*H
return target, apiErr, nil
}
func (c *Client) Update2(ctx context.Context, hostSetId string, version uint32, opt ...Option) (*HostSet, *api.Error, error) {
func (c *Client) Update(ctx context.Context, hostSetId string, version uint32, opt ...Option) (*HostSet, *api.Error, error) {
if hostSetId == "" {
return nil, nil, fmt.Errorf("empty hostSetId value passed into Update request")
}
@@ -358,13 +136,12 @@ func (c *Client) Update2(ctx context.Context, hostSetId string, version uint32,
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
if version == 0 {
if !opts.withAutomaticVersioning {
return nil, nil, errors.New("zero version number passed into Update request and automatic versioning not specified")
}
existingTarget, existingApiErr, existingErr := c.Read2(ctx, hostSetId, opt...)
existingTarget, existingApiErr, existingErr := c.Read(ctx, hostSetId, opt...)
if existingErr != nil {
return nil, nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
}
@@ -408,7 +185,7 @@ func (c *Client) Update2(ctx context.Context, hostSetId string, version uint32,
return target, apiErr, nil
}
func (c *Client) Delete2(ctx context.Context, hostSetId string, opt ...Option) (bool, *api.Error, error) {
func (c *Client) Delete(ctx context.Context, hostSetId string, opt ...Option) (bool, *api.Error, error) {
if hostSetId == "" {
return false, nil, fmt.Errorf("empty hostSetId value passed into Delete request")
}
@@ -417,7 +194,6 @@ func (c *Client) Delete2(ctx context.Context, hostSetId string, opt ...Option) (
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
req, err := c.client.NewRequest(ctx, "DELETE", fmt.Sprintf("host-sets/%s", hostSetId), nil, apiOpts...)
if err != nil {
@@ -451,7 +227,7 @@ func (c *Client) Delete2(ctx context.Context, hostSetId string, opt ...Option) (
return target.Existed, apiErr, nil
}
func (c *Client) List2(ctx context.Context, hostCatalogId string, opt ...Option) ([]*HostSet, *api.Error, error) {
func (c *Client) List(ctx context.Context, hostCatalogId string, opt ...Option) ([]*HostSet, *api.Error, error) {
if hostCatalogId == "" {
return nil, nil, fmt.Errorf("empty hostCatalogId value passed into List request")
}
@@ -460,7 +236,6 @@ func (c *Client) List2(ctx context.Context, hostCatalogId string, opt ...Option)
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
opts.queryMap["host_catalog_id"] = hostCatalogId
req, err := c.client.NewRequest(ctx, "GET", "host-sets", nil, apiOpts...)
@@ -495,10 +270,7 @@ func (c *Client) List2(ctx context.Context, hostCatalogId string, opt ...Option)
return target.Items, apiErr, nil
}
func (c *Client) AddHosts(ctx context.Context, hostCatalogId string, hostSetId string, version uint32, hostIds []string, opt ...Option) (*HostSet, *api.Error, error) {
if hostCatalogId == "" {
return nil, nil, fmt.Errorf("empty hostCatalogId value passed into AddHosts request")
}
func (c *Client) AddHosts(ctx context.Context, hostSetId string, version uint32, hostIds []string, opt ...Option) (*HostSet, *api.Error, error) {
if hostSetId == "" {
return nil, nil, fmt.Errorf("empty hostSetId value passed into AddHosts request")
}
@@ -512,203 +284,7 @@ func (c *Client) AddHosts(ctx context.Context, hostCatalogId string, hostSetId s
if !opts.withAutomaticVersioning {
return nil, nil, errors.New("zero version number passed into AddHosts request")
}
existingTarget, existingApiErr, existingErr := c.Read(ctx, hostCatalogId, hostSetId, opt...)
if existingErr != nil {
return nil, nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
}
if existingApiErr != nil {
return nil, nil, fmt.Errorf("error from controller when performing initial check-and-set read: %s", pretty.Sprint(existingApiErr))
}
if existingTarget == nil {
return nil, nil, errors.New("nil resource found when performing initial check-and-set read")
}
version = existingTarget.Version
}
opts.postMap["version"] = version
if len(hostIds) > 0 {
opts.postMap["host_ids"] = hostIds
}
req, err := c.client.NewRequest(ctx, "POST", fmt.Sprintf("host-catalogs/%s/host-sets/%s:add-hosts", hostCatalogId, hostSetId), opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating AddHosts request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
q.Add(k, v)
}
req.URL.RawQuery = q.Encode()
}
resp, err := c.client.Do(req)
if err != nil {
return nil, nil, fmt.Errorf("error performing client request during AddHosts call: %w", err)
}
target := new(HostSet)
apiErr, err := resp.Decode(target)
if err != nil {
return nil, nil, fmt.Errorf("error decoding AddHosts response: %w", err)
}
if apiErr != nil {
return nil, apiErr, nil
}
return target, apiErr, nil
}
func (c *Client) SetHosts(ctx context.Context, hostCatalogId string, hostSetId string, version uint32, hostIds []string, opt ...Option) (*HostSet, *api.Error, error) {
if hostCatalogId == "" {
return nil, nil, fmt.Errorf("empty hostCatalogId value passed into SetHosts request")
}
if hostSetId == "" {
return nil, nil, fmt.Errorf("empty hostSetId value passed into SetHosts request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
if version == 0 {
if !opts.withAutomaticVersioning {
return nil, nil, errors.New("zero version number passed into SetHosts request")
}
existingTarget, existingApiErr, existingErr := c.Read(ctx, hostCatalogId, hostSetId, opt...)
if existingErr != nil {
return nil, nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
}
if existingApiErr != nil {
return nil, nil, fmt.Errorf("error from controller when performing initial check-and-set read: %s", pretty.Sprint(existingApiErr))
}
if existingTarget == nil {
return nil, nil, errors.New("nil resource found when performing initial check-and-set read")
}
version = existingTarget.Version
}
opts.postMap["version"] = version
if len(hostIds) > 0 {
opts.postMap["host_ids"] = hostIds
} else if hostIds != nil {
// In this function, a non-nil but empty list means clear out
opts.postMap["host_ids"] = nil
}
req, err := c.client.NewRequest(ctx, "POST", fmt.Sprintf("host-catalogs/%s/host-sets/%s:set-hosts", hostCatalogId, hostSetId), opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating SetHosts request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
q.Add(k, v)
}
req.URL.RawQuery = q.Encode()
}
resp, err := c.client.Do(req)
if err != nil {
return nil, nil, fmt.Errorf("error performing client request during SetHosts call: %w", err)
}
target := new(HostSet)
apiErr, err := resp.Decode(target)
if err != nil {
return nil, nil, fmt.Errorf("error decoding SetHosts response: %w", err)
}
if apiErr != nil {
return nil, apiErr, nil
}
return target, apiErr, nil
}
func (c *Client) RemoveHosts(ctx context.Context, hostCatalogId string, hostSetId string, version uint32, hostIds []string, opt ...Option) (*HostSet, *api.Error, error) {
if hostCatalogId == "" {
return nil, nil, fmt.Errorf("empty hostCatalogId value passed into RemoveHosts request")
}
if hostSetId == "" {
return nil, nil, fmt.Errorf("empty hostSetId value passed into RemoveHosts request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
if version == 0 {
if !opts.withAutomaticVersioning {
return nil, nil, errors.New("zero version number passed into RemoveHosts request")
}
existingTarget, existingApiErr, existingErr := c.Read(ctx, hostCatalogId, hostSetId, opt...)
if existingErr != nil {
return nil, nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
}
if existingApiErr != nil {
return nil, nil, fmt.Errorf("error from controller when performing initial check-and-set read: %s", pretty.Sprint(existingApiErr))
}
if existingTarget == nil {
return nil, nil, errors.New("nil resource found when performing initial check-and-set read")
}
version = existingTarget.Version
}
opts.postMap["version"] = version
if len(hostIds) > 0 {
opts.postMap["host_ids"] = hostIds
}
req, err := c.client.NewRequest(ctx, "POST", fmt.Sprintf("host-catalogs/%s/host-sets/%s:remove-hosts", hostCatalogId, hostSetId), opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating RemoveHosts request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
q.Add(k, v)
}
req.URL.RawQuery = q.Encode()
}
resp, err := c.client.Do(req)
if err != nil {
return nil, nil, fmt.Errorf("error performing client request during RemoveHosts call: %w", err)
}
target := new(HostSet)
apiErr, err := resp.Decode(target)
if err != nil {
return nil, nil, fmt.Errorf("error decoding RemoveHosts response: %w", err)
}
if apiErr != nil {
return nil, apiErr, nil
}
return target, apiErr, nil
}
func (c *Client) AddHosts2(ctx context.Context, hostSetId string, version uint32, hostIds []string, opt ...Option) (*HostSet, *api.Error, error) {
if hostSetId == "" {
return nil, nil, fmt.Errorf("empty hostSetId value passed into AddHosts request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
if version == 0 {
if !opts.withAutomaticVersioning {
return nil, nil, errors.New("zero version number passed into AddHosts request")
}
existingTarget, existingApiErr, existingErr := c.Read2(ctx, hostSetId, opt...)
existingTarget, existingApiErr, existingErr := c.Read(ctx, hostSetId, opt...)
if existingErr != nil {
return nil, nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
}
@@ -756,7 +332,7 @@ func (c *Client) AddHosts2(ctx context.Context, hostSetId string, version uint32
return target, apiErr, nil
}
func (c *Client) SetHosts2(ctx context.Context, hostSetId string, version uint32, hostIds []string, opt ...Option) (*HostSet, *api.Error, error) {
func (c *Client) SetHosts(ctx context.Context, hostSetId string, version uint32, hostIds []string, opt ...Option) (*HostSet, *api.Error, error) {
if hostSetId == "" {
return nil, nil, fmt.Errorf("empty hostSetId value passed into SetHosts request")
}
@@ -765,13 +341,12 @@ func (c *Client) SetHosts2(ctx context.Context, hostSetId string, version uint32
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
if version == 0 {
if !opts.withAutomaticVersioning {
return nil, nil, errors.New("zero version number passed into SetHosts request")
}
existingTarget, existingApiErr, existingErr := c.Read2(ctx, hostSetId, opt...)
existingTarget, existingApiErr, existingErr := c.Read(ctx, hostSetId, opt...)
if existingErr != nil {
return nil, nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
}
@@ -822,7 +397,7 @@ func (c *Client) SetHosts2(ctx context.Context, hostSetId string, version uint32
return target, apiErr, nil
}
func (c *Client) RemoveHosts2(ctx context.Context, hostSetId string, version uint32, hostIds []string, opt ...Option) (*HostSet, *api.Error, error) {
func (c *Client) RemoveHosts(ctx context.Context, hostSetId string, version uint32, hostIds []string, opt ...Option) (*HostSet, *api.Error, error) {
if hostSetId == "" {
return nil, nil, fmt.Errorf("empty hostSetId value passed into RemoveHosts request")
}
@@ -831,13 +406,12 @@ func (c *Client) RemoveHosts2(ctx context.Context, hostSetId string, version uin
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
if version == 0 {
if !opts.withAutomaticVersioning {
return nil, nil, errors.New("zero version number passed into RemoveHosts request")
}
existingTarget, existingApiErr, existingErr := c.Read2(ctx, hostSetId, opt...)
existingTarget, existingApiErr, existingErr := c.Read(ctx, hostSetId, opt...)
if existingErr != nil {
return nil, nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
}
+153 -236
View File
@@ -18,129 +18,95 @@ import (
)
func TestCustom(t *testing.T) {
for _, newStyle := range []bool{false, true} {
t.Run(fmt.Sprintf("custom_%t", newStyle), func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
assert, require := assert.New(t), require.New(t)
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
token := tc.Token()
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
client := tc.Client().Clone()
client.SetScopeId(proj.GetPublicId())
client := tc.Client()
token := tc.Token()
client.SetToken(token.Token)
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
hc, apiErr, err := hostcatalogs.NewClient(client).Create(tc.Context(), "static")
require.NoError(err)
require.Nil(apiErr)
hc, apiErr, err := hostcatalogs.NewClient(client).Create(tc.Context(), "static", proj.GetPublicId())
require.NoError(err)
require.Nil(apiErr)
hClient := hosts.NewClient(client)
h1, apiErr, err := hClient.Create(tc.Context(), hc.Id, hosts.WithStaticHostAddress("someaddress"))
require.NoError(err)
require.Nil(apiErr)
h2, apiErr, err := hClient.Create(tc.Context(), hc.Id, hosts.WithStaticHostAddress("someaddress"))
require.NoError(err)
require.Nil(apiErr)
hClient := hosts.NewClient(client)
h1, apiErr, err := hClient.Create(tc.Context(), hc.Id, hosts.WithStaticHostAddress("someaddress"))
require.NoError(err)
require.Nil(apiErr)
h2, apiErr, err := hClient.Create(tc.Context(), hc.Id, hosts.WithStaticHostAddress("someaddress"))
require.NoError(err)
require.Nil(apiErr)
hSetClient := hostsets.NewClient(client)
var hSet *hostsets.HostSet
if newStyle {
hSet, apiErr, err = hSetClient.Create2(tc.Context(), hc.Id)
} else {
hSet, apiErr, err = hSetClient.Create(tc.Context(), hc.Id)
}
require.NoError(err)
require.Nil(apiErr)
hSetClient := hostsets.NewClient(client)
var hSet *hostsets.HostSet
hSet, apiErr, err = hSetClient.Create(tc.Context(), hc.Id)
require.NoError(err)
require.Nil(apiErr)
if newStyle {
hSet, apiErr, err = hSetClient.AddHosts2(tc.Context(), hSet.Id, hSet.Version, []string{h1.Id, h2.Id})
} else {
hSet, apiErr, err = hSetClient.AddHosts(tc.Context(), hc.Id, hSet.Id, hSet.Version, []string{h1.Id, h2.Id})
}
require.NoError(err)
require.Nil(apiErr)
assert.Contains(hSet.HostIds, h1.Id, h2.Id)
hSet, apiErr, err = hSetClient.AddHosts(tc.Context(), hSet.Id, hSet.Version, []string{h1.Id, h2.Id})
require.NoError(err)
require.Nil(apiErr)
assert.Contains(hSet.HostIds, h1.Id, h2.Id)
if newStyle {
hSet, apiErr, err = hSetClient.SetHosts2(tc.Context(), hSet.Id, hSet.Version, []string{h1.Id})
} else {
hSet, apiErr, err = hSetClient.SetHosts(tc.Context(), hc.Id, hSet.Id, hSet.Version, []string{h1.Id})
}
require.NoError(err)
require.Nil(apiErr, pretty.Sprint(apiErr))
assert.ElementsMatch([]string{h1.Id}, hSet.HostIds)
hSet, apiErr, err = hSetClient.SetHosts(tc.Context(), hSet.Id, hSet.Version, []string{h1.Id})
require.NoError(err)
require.Nil(apiErr, pretty.Sprint(apiErr))
assert.ElementsMatch([]string{h1.Id}, hSet.HostIds)
if newStyle {
hSet, apiErr, err = hSetClient.RemoveHosts2(tc.Context(), hSet.Id, hSet.Version, []string{h1.Id})
} else {
hSet, apiErr, err = hSetClient.RemoveHosts(tc.Context(), hc.Id, hSet.Id, hSet.Version, []string{h1.Id})
}
require.NoError(err)
require.Nil(apiErr)
assert.Empty(hSet.HostIds)
})
}
hSet, apiErr, err = hSetClient.RemoveHosts(tc.Context(), hSet.Id, hSet.Version, []string{h1.Id})
require.NoError(err)
require.Nil(apiErr)
assert.Empty(hSet.HostIds)
}
func TestSet_List(t *testing.T) {
for _, newStyle := range []bool{false, true} {
assert, require := assert.New(t), require.New(t)
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
func TestList(t *testing.T) {
assert, require := assert.New(t), require.New(t)
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
token := tc.Token()
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
client.SetScopeId(proj.GetPublicId())
client := tc.Client()
token := tc.Token()
client.SetToken(token.Token)
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
hc, apiErr, err := hostcatalogs.NewClient(client).Create(tc.Context(), "static")
require.NoError(err)
require.Nil(apiErr)
require.NotNil(hc)
hc, apiErr, err := hostcatalogs.NewClient(client).Create(tc.Context(), "static", proj.GetPublicId())
require.NoError(err)
require.Nil(apiErr)
require.NotNil(hc)
hClient := hostsets.NewClient(client)
var ul []*hostsets.HostSet
hClient := hostsets.NewClient(client)
var ul []*hostsets.HostSet
if newStyle {
ul, apiErr, err = hClient.List2(tc.Context(), hc.Id)
} else {
ul, apiErr, err = hClient.List(tc.Context(), hc.Id)
}
require.NoError(err)
require.Nil(apiErr)
assert.Empty(ul)
ul, apiErr, err = hClient.List(tc.Context(), hc.Id)
require.NoError(err)
require.Nil(apiErr)
assert.Empty(ul)
var expected []*hostsets.HostSet
for i := 0; i < 10; i++ {
expected = append(expected, &hostsets.HostSet{Name: fmt.Sprint(i)})
}
expected[0], apiErr, err = hClient.Create(tc.Context(), hc.Id, hostsets.WithName(expected[0].Name))
require.NoError(err)
require.Nil(apiErr)
if newStyle {
ul, apiErr, err = hClient.List2(tc.Context(), hc.Id)
} else {
ul, apiErr, err = hClient.List(tc.Context(), hc.Id)
}
require.NoError(err)
require.Nil(apiErr)
assert.ElementsMatch(comparableSetSlice(expected[:1]), comparableSetSlice(ul))
for i := 1; i < 10; i++ {
expected[i], apiErr, err = hClient.Create(tc.Context(), hc.Id, hostsets.WithName(expected[i].Name))
require.NoError(err)
require.Nil(apiErr)
}
if newStyle {
ul, apiErr, err = hClient.List2(tc.Context(), hc.Id)
} else {
ul, apiErr, err = hClient.List(tc.Context(), hc.Id)
}
require.NoError(err)
require.Nil(apiErr)
assert.ElementsMatch(comparableSetSlice(expected), comparableSetSlice(ul))
var expected []*hostsets.HostSet
for i := 0; i < 10; i++ {
expected = append(expected, &hostsets.HostSet{Name: fmt.Sprint(i)})
}
expected[0], apiErr, err = hClient.Create(tc.Context(), hc.Id, hostsets.WithName(expected[0].Name))
require.NoError(err)
require.Nil(apiErr)
ul, apiErr, err = hClient.List(tc.Context(), hc.Id)
require.NoError(err)
require.Nil(apiErr)
assert.ElementsMatch(comparableSetSlice(expected[:1]), comparableSetSlice(ul))
for i := 1; i < 10; i++ {
expected[i], apiErr, err = hClient.Create(tc.Context(), hc.Id, hostsets.WithName(expected[i].Name))
require.NoError(err)
require.Nil(apiErr)
}
ul, apiErr, err = hClient.List(tc.Context(), hc.Id)
require.NoError(err)
require.Nil(apiErr)
assert.ElementsMatch(comparableSetSlice(expected), comparableSetSlice(ul))
}
func comparableSetSlice(in []*hostsets.HostSet) []hostsets.HostSet {
@@ -158,146 +124,97 @@ func comparableSetSlice(in []*hostsets.HostSet) []hostsets.HostSet {
return filtered
}
func TestSet_Crud(t *testing.T) {
for _, newStyle := range []bool{false, true} {
t.Run(fmt.Sprintf("crud_%t", newStyle), func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
func TestCrud(t *testing.T) {
assert, require := assert.New(t), require.New(t)
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
token := tc.Token()
org, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
client.SetScopeId(org.GetPublicId())
projClient := client.Clone()
projClient.SetScopeId(proj.GetPublicId())
client := tc.Client()
token := tc.Token()
client.SetToken(token.Token)
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
hc, apiErr, err := hostcatalogs.NewClient(projClient).Create(tc.Context(), "static")
require.NoError(err)
require.Nil(apiErr)
require.NotNil(hc)
hc, apiErr, err := hostcatalogs.NewClient(client).Create(tc.Context(), "static", proj.GetPublicId())
require.NoError(err)
require.Nil(apiErr)
require.NotNil(hc)
checkHost := func(t *testing.T, step string, h *hostsets.HostSet, apiErr *api.Error, err error, wantedName string, wantVersion uint32) {
t.Helper()
require.NoError(err, step)
if !assert.Nil(apiErr, step) && apiErr.Message != "" {
t.Errorf("ApiError message: %q", apiErr.Message)
}
assert.NotNil(h, "returned no resource", step)
gotName := ""
if h.Name != "" {
gotName = h.Name
}
assert.Equal(wantedName, gotName, step)
assert.Equal(wantVersion, h.Version)
}
hClient := hostsets.NewClient(projClient)
var h *hostsets.HostSet
if newStyle {
h, apiErr, err = hClient.Create2(tc.Context(), hc.Id, hostsets.WithName("foo"))
} else {
h, apiErr, err = hClient.Create(tc.Context(), hc.Id, hostsets.WithName("foo"))
}
checkHost(t, "create", h, apiErr, err, "foo", 1)
if newStyle {
h, apiErr, err = hClient.Read2(tc.Context(), h.Id)
} else {
h, apiErr, err = hClient.Read(tc.Context(), hc.Id, h.Id)
}
checkHost(t, "read", h, apiErr, err, "foo", 1)
if newStyle {
h, apiErr, err = hClient.Update2(tc.Context(), h.Id, h.Version, hostsets.WithName("bar"))
} else {
h, apiErr, err = hClient.Update(tc.Context(), hc.Id, h.Id, h.Version, hostsets.WithName("bar"))
}
checkHost(t, "update", h, apiErr, err, "bar", 2)
if newStyle {
h, apiErr, err = hClient.Update2(tc.Context(), h.Id, h.Version, hostsets.DefaultName())
} else {
h, apiErr, err = hClient.Update(tc.Context(), hc.Id, h.Id, h.Version, hostsets.DefaultName())
}
checkHost(t, "update", h, apiErr, err, "", 3)
var existed bool
if newStyle {
existed, apiErr, err = hClient.Delete2(tc.Context(), h.Id)
} else {
existed, apiErr, err = hClient.Delete(tc.Context(), hc.Id, h.Id)
}
assert.NoError(err)
assert.True(existed, "Expected existing catalog when deleted, but it wasn't.")
if newStyle {
existed, apiErr, err = hClient.Delete2(tc.Context(), h.Id)
} else {
existed, apiErr, err = hClient.Delete(tc.Context(), hc.Id, h.Id)
}
require.NoError(err)
assert.NotNil(apiErr)
assert.EqualValues(http.StatusForbidden, apiErr.Status)
})
checkHost := func(t *testing.T, step string, h *hostsets.HostSet, apiErr *api.Error, err error, wantedName string, wantVersion uint32) {
t.Helper()
require.NoError(err, step)
if !assert.Nil(apiErr, step) && apiErr.Message != "" {
t.Errorf("ApiError message: %q", apiErr.Message)
}
assert.NotNil(h, "returned no resource", step)
gotName := ""
if h.Name != "" {
gotName = h.Name
}
assert.Equal(wantedName, gotName, step)
assert.Equal(wantVersion, h.Version)
}
hClient := hostsets.NewClient(client)
var h *hostsets.HostSet
h, apiErr, err = hClient.Create(tc.Context(), hc.Id, hostsets.WithName("foo"))
checkHost(t, "create", h, apiErr, err, "foo", 1)
h, apiErr, err = hClient.Read(tc.Context(), h.Id)
checkHost(t, "read", h, apiErr, err, "foo", 1)
h, apiErr, err = hClient.Update(tc.Context(), h.Id, h.Version, hostsets.WithName("bar"))
checkHost(t, "update", h, apiErr, err, "bar", 2)
h, apiErr, err = hClient.Update(tc.Context(), h.Id, h.Version, hostsets.DefaultName())
checkHost(t, "update", h, apiErr, err, "", 3)
var existed bool
existed, apiErr, err = hClient.Delete(tc.Context(), h.Id)
assert.NoError(err)
assert.True(existed, "Expected existing catalog when deleted, but it wasn't.")
existed, apiErr, err = hClient.Delete(tc.Context(), h.Id)
require.NoError(err)
assert.NotNil(apiErr)
assert.EqualValues(http.StatusForbidden, apiErr.Status)
}
// TODO: Get better coverage for expected errors and error formats.
func TestSet_Errors(t *testing.T) {
for _, newStyle := range []bool{false, true} {
assert, require := assert.New(t), require.New(t)
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
func TestErrors(t *testing.T) {
assert, require := assert.New(t), require.New(t)
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
token := tc.Token()
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
client.SetScopeId(proj.GetPublicId())
client := tc.Client()
token := tc.Token()
client.SetToken(token.Token)
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
hc, apiErr, err := hostcatalogs.NewClient(client).Create(tc.Context(), "static")
require.NoError(err)
require.Nil(apiErr)
require.NotNil(hc)
hc, apiErr, err := hostcatalogs.NewClient(client).Create(tc.Context(), "static", proj.GetPublicId())
require.NoError(err)
require.Nil(apiErr)
require.NotNil(hc)
hClient := hostsets.NewClient(client)
hClient := hostsets.NewClient(client)
var h *hostsets.HostSet
if newStyle {
h, apiErr, err = hClient.Create2(tc.Context(), hc.Id, hostsets.WithName("foo"))
} else {
h, apiErr, err = hClient.Create(tc.Context(), hc.Id, hostsets.WithName("foo"))
}
require.NoError(err)
require.Nil(apiErr)
assert.NotNil(h)
var h *hostsets.HostSet
h, apiErr, err = hClient.Create(tc.Context(), hc.Id, hostsets.WithName("foo"))
require.NoError(err)
require.Nil(apiErr)
assert.NotNil(h)
if newStyle {
h, apiErr, err = hClient.Create2(tc.Context(), hc.Id, hostsets.WithName("foo"))
} else {
h, apiErr, err = hClient.Create(tc.Context(), hc.Id, hostsets.WithName("foo"))
}
require.NoError(err)
assert.NotNil(apiErr)
assert.Nil(h)
h, apiErr, err = hClient.Create(tc.Context(), hc.Id, hostsets.WithName("foo"))
require.NoError(err)
assert.NotNil(apiErr)
assert.Nil(h)
if newStyle {
_, apiErr, err = hClient.Read2(tc.Context(), static.HostSetPrefix+"_doesntexis")
} else {
_, apiErr, err = hClient.Read(tc.Context(), hc.Id, static.HostSetPrefix+"_doesntexis")
}
require.NoError(err)
assert.NotNil(apiErr)
assert.EqualValues(http.StatusForbidden, apiErr.Status)
_, apiErr, err = hClient.Read(tc.Context(), static.HostSetPrefix+"_doesntexis")
require.NoError(err)
assert.NotNil(apiErr)
assert.EqualValues(http.StatusForbidden, apiErr.Status)
if newStyle {
_, apiErr, err = hClient.Read2(tc.Context(), "invalid id")
} else {
_, apiErr, err = hClient.Read(tc.Context(), hc.Id, "invalid id")
}
require.NoError(err)
assert.NotNil(apiErr)
assert.EqualValues(http.StatusBadRequest, apiErr.Status)
}
_, apiErr, err = hClient.Read(tc.Context(), "invalid id")
require.NoError(err)
assert.NotNil(apiErr)
assert.EqualValues(http.StatusBadRequest, apiErr.Status)
}
+2 -12
View File
@@ -16,7 +16,6 @@ type Option func(*options)
type options struct {
postMap map[string]interface{}
queryMap map[string]string
withScopeId string
withAutomaticVersioning bool
}
@@ -33,25 +32,16 @@ func getOpts(opt ...Option) (options, []api.Option) {
o(&opts)
}
var apiOpts []api.Option
if opts.withScopeId != "" {
apiOpts = append(apiOpts, api.WithScopeId(opts.withScopeId))
}
return opts, apiOpts
}
func WithScopeId(id string) Option {
return func(o *options) {
o.withScopeId = id
}
}
// If set, and if the version is zero during an update, the API will perform a
// fetch to get the current version of the resource and populate it during the
// update call. This is convenient but opens up the possibility for subtle
// order-of-modification issues, so use carefully.
func WithAutomaticVersioning() Option {
func WithAutomaticVersioning(enable bool) Option {
return func(o *options) {
o.withAutomaticVersioning = true
o.withAutomaticVersioning = enable
}
}
+17 -22
View File
@@ -47,6 +47,10 @@ type structInfo struct {
// the attributes map.
subtypeName string
// For non-top-level collections, this can be used to indicate the name of
// the argument that should be used
parentTypeName string
// mappings of names of resources and param names for sub slice types, e.g.
// role principals and group members
sliceSubTypes map[string]string
@@ -76,10 +80,6 @@ type structInfo struct {
// given type, e.g. arguments only valid for one call or purpose and not
// conveyed within the item itself
extraOptions []fieldInfo
useNewStyle bool
disableOldStyle bool
}
var inputStructs = []*structInfo{
@@ -231,7 +231,8 @@ var inputStructs = []*structInfo{
deleteTemplate,
listTemplate,
},
pathArgs: []string{"auth-method", "account"},
pathArgs: []string{"account"},
parentTypeName: "auth-method",
versionEnabled: true,
},
{
@@ -278,7 +279,8 @@ var inputStructs = []*structInfo{
deleteTemplate,
listTemplate,
},
pathArgs: []string{"host-catalog", "host"},
pathArgs: []string{"host"},
parentTypeName: "host-catalog",
versionEnabled: true,
},
{
@@ -296,18 +298,13 @@ var inputStructs = []*structInfo{
updateTemplate,
deleteTemplate,
listTemplate,
createTemplate2,
readTemplate2,
updateTemplate2,
deleteTemplate2,
listTemplate2,
},
pathArgs: []string{"host-catalog", "host-set"},
pathArgs: []string{"host-set"},
parentTypeName: "host-catalog",
sliceSubTypes: map[string]string{
"Hosts": "hostIds",
},
versionEnabled: true,
useNewStyle: true,
},
{
inProto: &targets.HostSet{},
@@ -318,19 +315,17 @@ var inputStructs = []*structInfo{
outFile: "targets/target.gen.go",
templates: []*template.Template{
clientTemplate,
createTemplate2,
readTemplate2,
updateTemplate2,
deleteTemplate2,
listTemplate2,
createTemplate,
readTemplate,
updateTemplate,
deleteTemplate,
listTemplate,
},
pathArgs: []string{"target"},
sliceSubTypes: map[string]string{
"HostSets": "hostSetIds",
},
versionEnabled: true,
typeOnCreate: true,
useNewStyle: true,
disableOldStyle: true,
versionEnabled: true,
typeOnCreate: true,
},
}
+69 -434
View File
@@ -39,32 +39,17 @@ func toPath(segments []string, action string) string {
return fmt.Sprintf("fmt.Sprintf(\"%s%s\", %s)", strings.Join(printfString, "/"), action, strings.Join(printfArg, ", "))
}
func getArgsAndPaths(in []string, action string) (colArgs, resArgs []string, colPath, resPath string) {
var argNames, pathSegment []string
for _, s := range in {
varName := fmt.Sprintf("%sId", strcase.ToLowerCamel(strings.ReplaceAll(s, "-", "_")))
collectionName := fmt.Sprintf("%ss", s)
argNames = append(argNames, varName)
pathSegment = append(pathSegment, collectionName, varName)
}
colArgs, resArgs, colPath, resPath = argNames[:len(argNames)-1], argNames, toPath(pathSegment[:len(pathSegment)-1], action), toPath(pathSegment, action)
// Scopes create and list operations always need scope ID
if colPath == `"scopes"` {
colArgs = append(colArgs, "scopeId")
}
return
}
func getArgsAndPathsNewStyle(in []string, action string) (colArg, resArg string, colPath, resPath string) {
func getArgsAndPaths(in []string, parentTypeName, action string) (colArg, resArg string, colPath, resPath string) {
resArg = fmt.Sprintf("%sId", strcase.ToLowerCamel(strings.ReplaceAll(in[len(in)-1], "-", "_")))
strToReplace := "scope"
if len(in) == 1 {
colArg = "scopeId"
if parentTypeName != "" {
strToReplace = parentTypeName
}
} else {
colArg = fmt.Sprintf("%sId", strcase.ToLowerCamel(strings.ReplaceAll(in[len(in)-2], "-", "_")))
strToReplace = in[len(in)-2]
}
colArg = fmt.Sprintf("%sId", strcase.ToLowerCamel(strings.ReplaceAll(strToReplace, "-", "_")))
colPath = fmt.Sprintf("%ss", in[len(in)-1])
if action != "" {
@@ -75,23 +60,19 @@ func getArgsAndPathsNewStyle(in []string, action string) (colArg, resArg string,
}
type templateInput struct {
Name string
Package string
Fields []fieldInfo
PathArgs []string
CollectionFunctionArgs []string
ResourceFunctionArgs []string
CollectionPath string
ResourcePath string
CollectionFunctionArg2 string
ResourceFunctionArg2 string
CollectionPath2 string
ResourcePath2 string
SliceSubTypes map[string]string
ExtraOptions []fieldInfo
VersionEnabled bool
TypeOnCreate bool
Two string
Name string
Package string
Fields []fieldInfo
PathArgs []string
CollectionFunctionArg string
ResourceFunctionArg string
CollectionPath string
ResourcePath string
ParentTypeName string
SliceSubTypes map[string]string
ExtraOptions []fieldInfo
VersionEnabled bool
TypeOnCreate bool
}
func fillTemplates() {
@@ -103,19 +84,14 @@ func fillTemplates() {
Package: in.generatedStructure.pkg,
Fields: in.generatedStructure.fields,
PathArgs: in.pathArgs,
ParentTypeName: in.parentTypeName,
ExtraOptions: in.extraOptions,
VersionEnabled: in.versionEnabled,
TypeOnCreate: in.typeOnCreate,
Two: "2",
}
if in.useNewStyle && in.disableOldStyle {
input.Two = ""
}
if len(in.pathArgs) > 0 {
input.CollectionFunctionArgs, input.ResourceFunctionArgs, input.CollectionPath, input.ResourcePath = getArgsAndPaths(in.pathArgs, "")
input.CollectionFunctionArg2, input.ResourceFunctionArg2, input.CollectionPath2, input.ResourcePath2 = getArgsAndPathsNewStyle(in.pathArgs, "")
input.CollectionFunctionArg, input.ResourceFunctionArg, input.CollectionPath, input.ResourcePath = getArgsAndPaths(in.pathArgs, in.parentTypeName, "")
}
if err := structTemplate.Execute(outBuf, input); err != nil {
@@ -125,12 +101,7 @@ func fillTemplates() {
if len(in.sliceSubTypes) > 0 {
input.SliceSubTypes = in.sliceSubTypes
if !in.disableOldStyle {
in.templates = append(in.templates, sliceSubTypeTemplate)
}
if in.useNewStyle {
in.templates = append(in.templates, sliceSubTypeTemplate2)
}
in.templates = append(in.templates, sliceSubTypeTemplate)
}
for _, t := range in.templates {
@@ -229,24 +200,23 @@ func fillTemplates() {
}
}
var listTemplate2 = template.Must(template.New("").Funcs(
var listTemplate = template.Must(template.New("").Funcs(
template.FuncMap{
"snakeCase": snakeCase,
},
).Parse(`
func (c *Client) List{{ .Two }}(ctx context.Context, {{ .CollectionFunctionArg2 }} string, opt... Option) ([]*{{ .Name }}, *api.Error, error) {
if {{ .CollectionFunctionArg2 }} == "" {
return nil, nil, fmt.Errorf("empty {{ .CollectionFunctionArg2 }} value passed into List request")
func (c *Client) List(ctx context.Context, {{ .CollectionFunctionArg }} string, opt... Option) ([]*{{ .Name }}, *api.Error, error) {
if {{ .CollectionFunctionArg }} == "" {
return nil, nil, fmt.Errorf("empty {{ .CollectionFunctionArg }} value passed into List request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
opts.queryMap["{{ snakeCase .CollectionFunctionArg2 }}"] = {{ .CollectionFunctionArg2 }}
opts.queryMap["{{ snakeCase .CollectionFunctionArg }}"] = {{ .CollectionFunctionArg }}
req, err := c.client.NewRequest(ctx, "GET", "{{ .CollectionPath2 }}", nil, apiOpts...)
req, err := c.client.NewRequest(ctx, "GET", "{{ .CollectionPath }}", nil, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating List request: %w", err)
}
@@ -281,101 +251,11 @@ func (c *Client) List{{ .Two }}(ctx context.Context, {{ .CollectionFunctionArg2
}
`))
var listTemplate = template.Must(template.New("").Parse(`
func (c *Client) List(ctx context.Context, {{ range .CollectionFunctionArgs }} {{ . }} string, {{ end }}opt... Option) ([]*{{ .Name }}, *api.Error, error) { {{ range .CollectionFunctionArgs }}
if {{ . }} == "" {
return nil, nil, fmt.Errorf("empty {{ . }} value passed into List request")
}
{{ end }}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
req, err := c.client.NewRequest(ctx, "GET", {{ .CollectionPath }}, nil, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating List request: %w", err)
}
{{ if ( eq .CollectionPath "\"scopes\"" ) }}
opts.queryMap["scope_id"] = scopeId
{{ end }}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
q.Add(k, v)
}
req.URL.RawQuery = q.Encode()
}
resp, err := c.client.Do(req)
if err != nil {
return nil, nil, fmt.Errorf("error performing client request during List call: %w", err)
}
type listResponse struct {
Items []*{{ .Name }}
}
target := &listResponse{}
apiErr, err := resp.Decode(target)
if err != nil {
return nil, nil, fmt.Errorf("error decoding List response: %w", err)
}
if apiErr != nil {
return nil, apiErr, nil
}
return target.Items, apiErr, nil
}
`))
var readTemplate2 = template.Must(template.New("").Parse(`
func (c *Client) Read{{ .Two }}(ctx context.Context, {{ .ResourceFunctionArg2 }} string, opt... Option) (*{{ .Name }}, *api.Error, error) {
if {{ .ResourceFunctionArg2 }} == "" {
return nil, nil, fmt.Errorf("empty {{ .ResourceFunctionArg2 }} value passed into Read request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
req, err := c.client.NewRequest(ctx, "GET", {{ .ResourcePath2 }}, nil, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Read request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
q.Add(k, v)
}
req.URL.RawQuery = q.Encode()
}
resp, err := c.client.Do(req)
if err != nil {
return nil, nil, fmt.Errorf("error performing client request during Read call: %w", err)
}
target := new({{ .Name }})
apiErr, err := resp.Decode(target)
if err != nil {
return nil, nil, fmt.Errorf("error decoding Read response: %w", err)
}
if apiErr != nil {
return nil, apiErr, nil
}
return target, apiErr, nil
}
`))
var readTemplate = template.Must(template.New("").Parse(`
func (c *Client) Read(ctx context.Context, {{ range .ResourceFunctionArgs }} {{ . }} string, {{ end }} opt... Option) (*{{ .Name }}, *api.Error, error) { {{ range .ResourceFunctionArgs }}
if {{ . }} == "" {
return nil, nil, fmt.Errorf("empty {{ . }} value passed into Read request")
func (c *Client) Read(ctx context.Context, {{ .ResourceFunctionArg }} string, opt... Option) (*{{ .Name }}, *api.Error, error) {
if {{ .ResourceFunctionArg }} == "" {
return nil, nil, fmt.Errorf("empty {{ .ResourceFunctionArg }} value passed into Read request")
}
{{ end }}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
@@ -412,57 +292,11 @@ func (c *Client) Read(ctx context.Context, {{ range .ResourceFunctionArgs }} {{
}
`))
var deleteTemplate2 = template.Must(template.New("").Parse(`
func (c *Client) Delete{{ .Two }}(ctx context.Context, {{ .ResourceFunctionArg2 }} string, opt... Option) (bool, *api.Error, error) {
if {{ .ResourceFunctionArg2 }} == "" {
return false, nil, fmt.Errorf("empty {{ .ResourceFunctionArg2 }} value passed into Delete request")
}
if c.client == nil {
return false, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
req, err := c.client.NewRequest(ctx, "DELETE", {{ .ResourcePath2 }}, nil, apiOpts...)
if err != nil {
return false, nil, fmt.Errorf("error creating Delete request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
q.Add(k, v)
}
req.URL.RawQuery = q.Encode()
}
resp, err := c.client.Do(req)
if err != nil {
return false, nil, fmt.Errorf("error performing client request during Delete call: %w", err)
}
type deleteResponse struct {
Existed bool
}
target := &deleteResponse{}
apiErr, err := resp.Decode(target)
if err != nil {
return false, nil, fmt.Errorf("error decoding Delete response: %w", err)
}
if apiErr != nil {
return false, apiErr, nil
}
return target.Existed, apiErr, nil
}
`))
var deleteTemplate = template.Must(template.New("").Parse(`
func (c *Client) Delete(ctx context.Context, {{ range .ResourceFunctionArgs }} {{ . }} string, {{ end }} opt... Option) (bool, *api.Error, error) { {{ range .ResourceFunctionArgs }}
if {{ . }} == "" {
return false, nil, fmt.Errorf("empty {{ . }} value passed into Delete request")
func (c *Client) Delete(ctx context.Context, {{ .ResourceFunctionArg }} string, opt... Option) (bool, *api.Error, error) {
if {{ .ResourceFunctionArg }} == "" {
return false, nil, fmt.Errorf("empty {{ .ResourceFunctionArg }} value passed into Delete request")
}
{{ end }}
if c.client == nil {
return false, nil, fmt.Errorf("nil client")
}
@@ -502,17 +336,18 @@ func (c *Client) Delete(ctx context.Context, {{ range .ResourceFunctionArgs }} {
}
`))
var createTemplate2 = template.Must(template.New("").Funcs(
var createTemplate = template.Must(template.New("").Funcs(
template.FuncMap{
"snakeCase": snakeCase,
},
).Parse(`
func (c *Client) Create{{ .Two }} (ctx context.Context, {{ if .TypeOnCreate }} resourceType string, {{ end }} {{ .CollectionFunctionArg2 }} string, opt... Option) (*{{ .Name }}, *api.Error, error) {
if {{ .CollectionFunctionArg2 }} == "" {
return nil, nil, fmt.Errorf("empty {{ .CollectionFunctionArg2 }} value passed into Create request")
func (c *Client) Create (ctx context.Context, {{ if .TypeOnCreate }} resourceType string, {{ end }} {{ .CollectionFunctionArg }} string, opt... Option) (*{{ .Name }}, *api.Error, error) {
if {{ .CollectionFunctionArg }} == "" {
return nil, nil, fmt.Errorf("empty {{ .CollectionFunctionArg }} value passed into Create request")
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
@@ -522,9 +357,9 @@ func (c *Client) Create{{ .Two }} (ctx context.Context, {{ if .TypeOnCreate }} r
opts.postMap["type"] = resourceType
}{{ end }}
opts.postMap["{{ snakeCase .CollectionFunctionArg2 }}"] = {{ .CollectionFunctionArg2 }}
opts.postMap["{{ snakeCase .CollectionFunctionArg }}"] = {{ .CollectionFunctionArg }}
req, err := c.client.NewRequest(ctx, "POST", "{{ .CollectionPath2 }}", opts.postMap, apiOpts...)
req, err := c.client.NewRequest(ctx, "POST", "{{ .CollectionPath }}", opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Create request: %w", err)
}
@@ -556,121 +391,11 @@ func (c *Client) Create{{ .Two }} (ctx context.Context, {{ if .TypeOnCreate }} r
}
`))
var createTemplate = template.Must(template.New("").Parse(`
func (c *Client) Create(ctx context.Context, {{ if .TypeOnCreate }} resourceType string, {{ end }} {{ range .CollectionFunctionArgs }} {{ . }} string, {{ end }} opt... Option) (*{{ .Name }}, *api.Error, error) { {{ range .CollectionFunctionArgs }}
if {{ . }} == "" {
return nil, nil, fmt.Errorf("empty {{ . }} value passed into Create request")
}
{{ end }}opts, apiOpts := getOpts(opt...)
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
{{ if .TypeOnCreate }} if resourceType == "" {
return nil, nil, fmt.Errorf("empty resourceType value passed into Create request")
} else {
opts.postMap["type"] = resourceType
}{{ end }}
{{ if ( eq .CollectionPath "\"scopes\"" ) }}
opts.postMap["scope_id"] = scopeId
{{ end }}
req, err := c.client.NewRequest(ctx, "POST", {{ .CollectionPath }}, opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Create request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
q.Add(k, v)
}
req.URL.RawQuery = q.Encode()
}
resp, err := c.client.Do(req)
if err != nil {
return nil, nil, fmt.Errorf("error performing client request during Create call: %w", err)
}
target := new({{ .Name }})
apiErr, err := resp.Decode(target)
if err != nil {
return nil, nil, fmt.Errorf("error decoding Create response: %w", err)
}
if apiErr != nil {
return nil, apiErr, nil
}
return target, apiErr, nil
}
`))
var updateTemplate2 = template.Must(template.New("").Parse(`
func (c *Client) Update{{ .Two }}(ctx context.Context, {{ .ResourceFunctionArg2 }} string, version uint32, opt... Option) (*{{ .Name }}, *api.Error, error) {
if {{ .ResourceFunctionArg2 }} == "" {
return nil, nil, fmt.Errorf("empty {{ .ResourceFunctionArg2 }} value passed into Update request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
{{ if .VersionEnabled }}
if version == 0 {
if !opts.withAutomaticVersioning {
return nil, nil, errors.New("zero version number passed into Update request and automatic versioning not specified")
}
existingTarget, existingApiErr, existingErr := c.Read{{ .Two }}(ctx, {{ .ResourceFunctionArg2 }}, opt...)
if existingErr != nil {
return nil, nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
}
if existingApiErr != nil {
return nil, nil, fmt.Errorf("error from controller when performing initial check-and-set read: %s", pretty.Sprint(existingApiErr))
}
if existingTarget == nil {
return nil, nil, errors.New("nil resource found when performing initial check-and-set read")
}
version = existingTarget.Version
}
{{ end }}
opts.postMap["version"] = version
req, err := c.client.NewRequest(ctx, "PATCH", {{ .ResourcePath2 }}, opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Update request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
q.Add(k, v)
}
req.URL.RawQuery = q.Encode()
}
resp, err := c.client.Do(req)
if err != nil {
return nil, nil, fmt.Errorf("error performing client request during Update call: %w", err)
}
target := new({{ .Name }})
apiErr, err := resp.Decode(target)
if err != nil {
return nil, nil, fmt.Errorf("error decoding Update response: %w", err)
}
if apiErr != nil {
return nil, apiErr, nil
}
return target, apiErr, nil
}
`))
var updateTemplate = template.Must(template.New("").Parse(`
func (c *Client) Update(ctx context.Context, {{ range .ResourceFunctionArgs }} {{ . }} string, {{ end }}version uint32, opt... Option) (*{{ .Name }}, *api.Error, error) { {{ range .ResourceFunctionArgs }}
if {{ . }} == "" {
return nil, nil, fmt.Errorf("empty {{ . }} value passed into Update request")
}{{ end }}
func (c *Client) Update(ctx context.Context, {{ .ResourceFunctionArg }} string, version uint32, opt... Option) (*{{ .Name }}, *api.Error, error) {
if {{ .ResourceFunctionArg }} == "" {
return nil, nil, fmt.Errorf("empty {{ .ResourceFunctionArg }} value passed into Update request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
@@ -682,7 +407,7 @@ func (c *Client) Update(ctx context.Context, {{ range .ResourceFunctionArgs }} {
if !opts.withAutomaticVersioning {
return nil, nil, errors.New("zero version number passed into Update request and automatic versioning not specified")
}
existingTarget, existingApiErr, existingErr := c.Read(ctx, {{ range .ResourceFunctionArgs }} {{ . }}, {{ end }} opt...)
existingTarget, existingApiErr, existingErr := c.Read(ctx, {{ .ResourceFunctionArg }}, opt...)
if existingErr != nil {
return nil, nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
}
@@ -741,11 +466,11 @@ var sliceSubTypeTemplate = template.Must(template.New("").Funcs(
{{ range $key, $value := $input.SliceSubTypes }}
{{ $fullName := print $op $key }}
{{ $actionName := kebabCase $fullName }}
{{ $resPath := getPathWithAction $input.PathArgs $actionName }}
func (c *Client) {{ $fullName }}(ctx context.Context, {{ range $input.ResourceFunctionArgs }} {{ . }} string, {{ end }}version uint32, {{ $value }} []string, opt... Option) (*{{ $input.Name }}, *api.Error, error) { {{ range $input.ResourceFunctionArgs }}
if {{ . }} == "" {
return nil, nil, fmt.Errorf("empty {{ . }} value passed into {{ $fullName }} request")
}{{ end }}
{{ $resPath := getPathWithAction $input.PathArgs $input.ParentTypeName $actionName }}
func (c *Client) {{ $fullName }}(ctx context.Context, {{ $input.ResourceFunctionArg }} string, version uint32, {{ $value }} []string, opt... Option) (*{{ $input.Name }}, *api.Error, error) {
if {{ $input.ResourceFunctionArg }} == "" {
return nil, nil, fmt.Errorf("empty {{ $input.ResourceFunctionArg }} value passed into {{ $fullName }} request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
@@ -757,92 +482,7 @@ func (c *Client) {{ $fullName }}(ctx context.Context, {{ range $input.ResourceFu
if !opts.withAutomaticVersioning {
return nil, nil, errors.New("zero version number passed into {{ $fullName }} request")
}
existingTarget, existingApiErr, existingErr := c.Read(ctx, {{ range $input.ResourceFunctionArgs }} {{ . }}, {{ end }} opt...)
if existingErr != nil {
return nil, nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
}
if existingApiErr != nil {
return nil, nil, fmt.Errorf("error from controller when performing initial check-and-set read: %s", pretty.Sprint(existingApiErr))
}
if existingTarget == nil {
return nil, nil, errors.New("nil resource found when performing initial check-and-set read")
}
version = existingTarget.Version
}
{{ end }}
opts.postMap["version"] = version
if len({{ $value }}) > 0 {
opts.postMap["{{ snakeCase $value }}"] = {{ $value }}
}{{ if ( eq $op "Set" ) }} else if {{ $value }} != nil {
// In this function, a non-nil but empty list means clear out
opts.postMap["{{ snakeCase $value }}"] = nil
}
{{ end }}
req, err := c.client.NewRequest(ctx, "POST", {{ $resPath }}, opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating {{ $fullName }} request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
q.Add(k, v)
}
req.URL.RawQuery = q.Encode()
}
resp, err := c.client.Do(req)
if err != nil {
return nil, nil, fmt.Errorf("error performing client request during {{ $fullName }} call: %w", err)
}
target := new({{ $input.Name }})
apiErr, err := resp.Decode(target)
if err != nil {
return nil, nil, fmt.Errorf("error decoding {{ $fullName }} response: %w", err)
}
if apiErr != nil {
return nil, apiErr, nil
}
return target, apiErr, nil
}
{{ end }}
{{ end }}
`))
var sliceSubTypeTemplate2 = template.Must(template.New("").Funcs(
template.FuncMap{
"makeSlice": makeSlice,
"snakeCase": snakeCase,
"kebabCase": kebabCase,
"getPathWithActionNewStyle": getPathWithActionNewStyle,
},
).Parse(`
{{ $input := . }}
{{ range $index, $op := makeSlice "Add" "Set" "Remove" }}
{{ range $key, $value := $input.SliceSubTypes }}
{{ $fullName := print $op $key }}
{{ $actionName := kebabCase $fullName }}
{{ $resPath := getPathWithActionNewStyle $input.PathArgs $actionName }}
func (c *Client) {{ $fullName }}{{ $input.Two }}(ctx context.Context, {{ $input.ResourceFunctionArg2 }} string, version uint32, {{ $value }} []string, opt... Option) (*{{ $input.Name }}, *api.Error, error) {
if {{ $input.ResourceFunctionArg2 }} == "" {
return nil, nil, fmt.Errorf("empty {{ $input.ResourceFunctionArg2 }} value passed into {{ $fullName }} request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
{{ if $input.VersionEnabled }}
if version == 0 {
if !opts.withAutomaticVersioning {
return nil, nil, errors.New("zero version number passed into {{ $fullName }} request")
}
existingTarget, existingApiErr, existingErr := c.Read{{ $input.Two }}(ctx, {{ $input.ResourceFunctionArg2 }}, opt...)
existingTarget, existingApiErr, existingErr := c.Read(ctx, {{ $input.ResourceFunctionArg }}, opt...)
if existingErr != nil {
return nil, nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
}
@@ -918,12 +558,22 @@ type {{ .Name }} struct { {{ range .Fields }}
`)))
var clientTemplate = template.Must(template.New("").Parse(`
// Client is a client for this collection
type Client struct {
client *api.Client
}
// Creates a new client for this collection. The submitted API client is cloned;
// modifications to it after generating this client will not have effect. If you
// need to make changes to the underlying API client, use ApiClient() to access
// it.
func NewClient(c *api.Client) *Client {
return &Client{ client: c }
return &Client{ client: c.Clone() }
}
// ApiClient returns the underlying API client
func (c *Client) ApiClient() *api.Client {
return c.client
}
`))
@@ -950,7 +600,6 @@ type Option func(*options)
type options struct {
postMap map[string]interface{}
queryMap map[string]string
withScopeId string
withAutomaticVersioning bool
}
@@ -967,25 +616,16 @@ func getOpts(opt ...Option) (options, []api.Option) {
o(&opts)
}
var apiOpts []api.Option
if opts.withScopeId != "" {
apiOpts = append(apiOpts, api.WithScopeId(opts.withScopeId))
}
return opts, apiOpts
}
func WithScopeId(id string) Option {
return func(o *options) {
o.withScopeId = id
}
}
// If set, and if the version is zero during an update, the API will perform a
// fetch to get the current version of the resource and populate it during the
// update call. This is convenient but opens up the possibility for subtle
// order-of-modification issues, so use carefully.
func WithAutomaticVersioning() Option {
func WithAutomaticVersioning(enable bool) Option {
return func(o *options) {
o.withAutomaticVersioning = true
o.withAutomaticVersioning = enable
}
}
{{ range .Fields }}
@@ -1033,12 +673,7 @@ func kebabCase(in string) string {
return strcase.ToKebab(in)
}
func getPathWithAction(resArgs []string, action string) string {
_, _, _, resPath := getArgsAndPaths(resArgs, action)
return resPath
}
func getPathWithActionNewStyle(resArgs []string, action string) string {
_, _, _, resPath := getArgsAndPathsNewStyle(resArgs, action)
func getPathWithAction(resArgs []string, parentTypeName, action string) string {
_, _, _, resPath := getArgsAndPaths(resArgs, parentTypeName, action)
return resPath
}
+1 -17
View File
@@ -13,24 +13,8 @@ type Option func(*options)
// options = how options are represented
type options struct {
withScopeId string
withNewStyle bool
}
func getDefaultOptions() options {
return options{
withScopeId: "",
}
}
func WithScopeId(id string) Option {
return func(o *options) {
o.withScopeId = id
}
}
func WithNewStyle() Option {
return func(o *options) {
o.withNewStyle = true
}
return options{}
}
+2 -12
View File
@@ -16,7 +16,6 @@ type Option func(*options)
type options struct {
postMap map[string]interface{}
queryMap map[string]string
withScopeId string
withAutomaticVersioning bool
}
@@ -33,25 +32,16 @@ func getOpts(opt ...Option) (options, []api.Option) {
o(&opts)
}
var apiOpts []api.Option
if opts.withScopeId != "" {
apiOpts = append(apiOpts, api.WithScopeId(opts.withScopeId))
}
return opts, apiOpts
}
func WithScopeId(id string) Option {
return func(o *options) {
o.withScopeId = id
}
}
// If set, and if the version is zero during an update, the API will perform a
// fetch to get the current version of the resource and populate it during the
// update call. This is convenient but opens up the possibility for subtle
// order-of-modification issues, so use carefully.
func WithAutomaticVersioning() Option {
func WithAutomaticVersioning(enable bool) Option {
return func(o *options) {
o.withAutomaticVersioning = true
o.withAutomaticVersioning = enable
}
}
+26 -6
View File
@@ -30,24 +30,42 @@ type Role struct {
Grants []*Grant `json:"grants,omitempty"`
}
// Client is a client for this collection
type Client struct {
client *api.Client
}
// Creates a new client for this collection. The submitted API client is cloned;
// modifications to it after generating this client will not have effect. If you
// need to make changes to the underlying API client, use ApiClient() to access
// it.
func NewClient(c *api.Client) *Client {
return &Client{client: c}
return &Client{client: c.Clone()}
}
func (c *Client) Create(ctx context.Context, opt ...Option) (*Role, *api.Error, error) {
// ApiClient returns the underlying API client
func (c *Client) ApiClient() *api.Client {
return c.client
}
func (c *Client) Create(ctx context.Context, scopeId string, opt ...Option) (*Role, *api.Error, error) {
if scopeId == "" {
return nil, nil, fmt.Errorf("empty scopeId value passed into Create request")
}
opts, apiOpts := getOpts(opt...)
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts.postMap["scope_id"] = scopeId
req, err := c.client.NewRequest(ctx, "POST", "roles", opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Create request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
@@ -74,9 +92,8 @@ func (c *Client) Create(ctx context.Context, opt ...Option) (*Role, *api.Error,
func (c *Client) Read(ctx context.Context, roleId string, opt ...Option) (*Role, *api.Error, error) {
if roleId == "" {
return nil, nil, fmt.Errorf("empty roleId value passed into Read request")
return nil, nil, fmt.Errorf("empty roleId value passed into Read request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
@@ -174,7 +191,6 @@ func (c *Client) Delete(ctx context.Context, roleId string, opt ...Option) (bool
if roleId == "" {
return false, nil, fmt.Errorf("empty roleId value passed into Delete request")
}
if c.client == nil {
return false, nil, fmt.Errorf("nil client")
}
@@ -213,12 +229,16 @@ func (c *Client) Delete(ctx context.Context, roleId string, opt ...Option) (bool
return target.Existed, apiErr, nil
}
func (c *Client) List(ctx context.Context, opt ...Option) ([]*Role, *api.Error, error) {
func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*Role, *api.Error, error) {
if scopeId == "" {
return nil, nil, fmt.Errorf("empty scopeId value passed into List request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
opts.queryMap["scope_id"] = scopeId
req, err := c.client.NewRequest(ctx, "GET", "roles", nil, apiOpts...)
if err != nil {
+65 -91
View File
@@ -18,36 +18,29 @@ import (
func TestCustom(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org, proj := iam.TestScopes(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
projClient := client.Clone()
projClient.SetScopeId(proj.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
org, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
cases := []struct {
name string
scopeClient *api.Client
name string
scopeId string
}{
{
name: "org",
scopeClient: client,
name: "org",
scopeId: org.GetPublicId(),
},
{
name: "proj",
scopeClient: projClient,
name: "proj",
scopeId: proj.GetPublicId(),
},
}
user, apiErr, err := users.NewClient(client).Create(tc.Context())
user, apiErr, err := users.NewClient(client).Create(tc.Context(), org.GetPublicId())
require.NoError(err)
require.Nil(apiErr)
@@ -69,15 +62,15 @@ func TestCustom(t *testing.T) {
for _, tt := range cases {
t.Run(tt.name, func(t *testing.T) {
g, apiErr, err := groups.NewClient(tt.scopeClient).Create(tc.Context())
g, apiErr, err := groups.NewClient(client).Create(tc.Context(), tt.scopeId)
require.NoError(err)
require.Nil(apiErr)
require.NotNil(g)
rc := roles.NewClient(tt.scopeClient)
rc := roles.NewClient(client)
var version uint32 = 1
r, apiErr, err := rc.Create(tc.Context(), roles.WithName("foo"))
r, apiErr, err := rc.Create(tc.Context(), tt.scopeId, roles.WithName("foo"))
require.NoError(err)
require.Nil(apiErr)
require.NotNil(r)
@@ -129,65 +122,60 @@ func TestCustom(t *testing.T) {
}
}
func TestRole_List(t *testing.T) {
func TestList(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org, proj := iam.TestScopes(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
projClient := client.Clone()
projClient.SetScopeId(proj.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
org, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
cases := []struct {
name string
scopeClient *api.Client
name string
scopeId string
}{
{
name: "org",
scopeClient: client,
name: "org",
scopeId: org.GetPublicId(),
},
{
name: "proj",
scopeClient: projClient,
name: "proj",
scopeId: proj.GetPublicId(),
},
}
for _, tt := range cases {
t.Run(tt.name, func(t *testing.T) {
roleClient := roles.NewClient(tt.scopeClient)
p1, apiErr, err := roleClient.List(tc.Context())
var expected []*roles.Role
roleClient := roles.NewClient(client)
p1, apiErr, err := roleClient.List(tc.Context(), tt.scopeId)
require.NoError(err)
assert.Nil(apiErr)
require.Len(p1, 0)
require.Len(p1, 1)
expected = append(expected, p1[0])
var expected []*roles.Role
for i := 0; i < 10; i++ {
for i := 1; i < 11; i++ {
expected = append(expected, &roles.Role{Name: fmt.Sprint(i)})
}
expected[0], apiErr, err = roleClient.Create(tc.Context(), roles.WithName(expected[0].Name))
expected[1], apiErr, err = roleClient.Create(tc.Context(), tt.scopeId, roles.WithName(expected[1].Name))
require.NoError(err)
assert.Nil(apiErr)
p2, apiErr, err := roleClient.List(tc.Context())
p2, apiErr, err := roleClient.List(tc.Context(), tt.scopeId)
assert.NoError(err)
assert.Nil(apiErr)
assert.ElementsMatch(comparableSlice(expected[:1]), comparableSlice(p2))
assert.ElementsMatch(comparableSlice(expected[0:2]), comparableSlice(p2))
for i := 1; i < 10; i++ {
expected[i], apiErr, err = roleClient.Create(tc.Context(), roles.WithName(expected[i].Name))
for i := 2; i < 11; i++ {
expected[i], apiErr, err = roleClient.Create(tc.Context(), tt.scopeId, roles.WithName(expected[i].Name))
assert.NoError(err)
assert.Nil(apiErr)
}
p3, apiErr, err := roleClient.List(tc.Context())
p3, apiErr, err := roleClient.List(tc.Context(), tt.scopeId)
require.NoError(err)
assert.Nil(apiErr)
assert.ElementsMatch(comparableSlice(expected), comparableSlice(p3))
@@ -210,34 +198,27 @@ func comparableSlice(in []*roles.Role) []roles.Role {
return filtered
}
func TestRole_Crud(t *testing.T) {
func TestCrud(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org, proj := iam.TestScopes(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
projClient := client.Clone()
projClient.SetScopeId(proj.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
org, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
cases := []struct {
name string
scopeClient *api.Client
name string
scopeId string
}{
{
name: "org",
scopeClient: client,
name: "org",
scopeId: org.GetPublicId(),
},
{
name: "proj",
scopeClient: projClient,
name: "proj",
scopeId: proj.GetPublicId(),
},
}
@@ -257,8 +238,8 @@ func TestRole_Crud(t *testing.T) {
for _, tt := range cases {
t.Run(tt.name, func(t *testing.T) {
roleClient := roles.NewClient(tt.scopeClient)
g, apiErr, err := roleClient.Create(tc.Context(), roles.WithName("foo"))
roleClient := roles.NewClient(client)
g, apiErr, err := roleClient.Create(tc.Context(), tt.scopeId, roles.WithName("foo"))
checkRole("create", g, apiErr, err, "foo", 1)
g, apiErr, err = roleClient.Read(tc.Context(), g.Id)
@@ -278,47 +259,40 @@ func TestRole_Crud(t *testing.T) {
}
}
func TestRole_Errors(t *testing.T) {
func TestErrors(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org, proj := iam.TestScopes(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
projClient := client.Clone()
projClient.SetScopeId(proj.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
org, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
cases := []struct {
name string
scopeClient *api.Client
name string
scopeId string
}{
{
name: "org",
scopeClient: client,
name: "org",
scopeId: org.GetPublicId(),
},
{
name: "proj",
scopeClient: projClient,
name: "proj",
scopeId: proj.GetPublicId(),
},
}
for _, tt := range cases {
t.Run(tt.name, func(t *testing.T) {
roleClient := roles.NewClient(tt.scopeClient)
u, apiErr, err := roleClient.Create(tc.Context(), roles.WithName("first"))
roleClient := roles.NewClient(client)
u, apiErr, err := roleClient.Create(tc.Context(), tt.scopeId, roles.WithName("first"))
require.NoError(err)
assert.Nil(apiErr)
assert.NotNil(u)
// Create another resource with the same name.
_, apiErr, err = roleClient.Create(tc.Context(), roles.WithName("first"))
_, apiErr, err = roleClient.Create(tc.Context(), tt.scopeId, roles.WithName("first"))
require.NoError(err)
assert.NotNil(apiErr)
+2 -12
View File
@@ -18,7 +18,6 @@ type Option func(*options)
type options struct {
postMap map[string]interface{}
queryMap map[string]string
withScopeId string
withAutomaticVersioning bool
}
@@ -35,25 +34,16 @@ func getOpts(opt ...Option) (options, []api.Option) {
o(&opts)
}
var apiOpts []api.Option
if opts.withScopeId != "" {
apiOpts = append(apiOpts, api.WithScopeId(opts.withScopeId))
}
return opts, apiOpts
}
func WithScopeId(id string) Option {
return func(o *options) {
o.withScopeId = id
}
}
// If set, and if the version is zero during an update, the API will perform a
// fetch to get the current version of the resource and populate it during the
// update call. This is convenient but opens up the possibility for subtle
// order-of-modification issues, so use carefully.
func WithAutomaticVersioning() Option {
func WithAutomaticVersioning(enable bool) Option {
return func(o *options) {
o.withAutomaticVersioning = true
o.withAutomaticVersioning = enable
}
}
+15 -30
View File
@@ -13,20 +13,15 @@ import (
"github.com/stretchr/testify/require"
)
func TestProjects_List(t *testing.T) {
func TestList(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org := iam.TestOrg(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
org := iam.TestOrg(t, tc.IamRepo(), iam.WithUserId(token.UserId))
scps := scopes.NewClient(client)
@@ -63,20 +58,15 @@ func comparableSlice(in []*scopes.Scope) []scopes.Scope {
return filtered
}
func TestProjects_Crud(t *testing.T) {
func TestCrud(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org, _ := iam.TestScopes(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
org, _ := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
scps := scopes.NewClient(client)
@@ -116,20 +106,15 @@ func TestProjects_Crud(t *testing.T) {
}
// TODO: Get better coverage for expected errors and error formats.
func TestProject_Errors(t *testing.T) {
func TestErrors(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org, _ := iam.TestScopes(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
org, _ := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
scps := scopes.NewClient(client)
+16 -7
View File
@@ -24,19 +24,31 @@ type Scope struct {
Version uint32 `json:"version,omitempty"`
}
// Client is a client for this collection
type Client struct {
client *api.Client
}
// Creates a new client for this collection. The submitted API client is cloned;
// modifications to it after generating this client will not have effect. If you
// need to make changes to the underlying API client, use ApiClient() to access
// it.
func NewClient(c *api.Client) *Client {
return &Client{client: c}
return &Client{client: c.Clone()}
}
// ApiClient returns the underlying API client
func (c *Client) ApiClient() *api.Client {
return c.client
}
func (c *Client) Create(ctx context.Context, scopeId string, opt ...Option) (*Scope, *api.Error, error) {
if scopeId == "" {
return nil, nil, fmt.Errorf("empty scopeId value passed into Create request")
}
opts, apiOpts := getOpts(opt...)
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
@@ -47,6 +59,7 @@ func (c *Client) Create(ctx context.Context, scopeId string, opt ...Option) (*Sc
if err != nil {
return nil, nil, fmt.Errorf("error creating Create request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
@@ -73,9 +86,8 @@ func (c *Client) Create(ctx context.Context, scopeId string, opt ...Option) (*Sc
func (c *Client) Read(ctx context.Context, scopeId string, opt ...Option) (*Scope, *api.Error, error) {
if scopeId == "" {
return nil, nil, fmt.Errorf("empty scopeId value passed into Read request")
return nil, nil, fmt.Errorf("empty scopeId value passed into Read request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
@@ -173,7 +185,6 @@ func (c *Client) Delete(ctx context.Context, scopeId string, opt ...Option) (boo
if scopeId == "" {
return false, nil, fmt.Errorf("empty scopeId value passed into Delete request")
}
if c.client == nil {
return false, nil, fmt.Errorf("nil client")
}
@@ -216,20 +227,18 @@ func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*Sc
if scopeId == "" {
return nil, nil, fmt.Errorf("empty scopeId value passed into List request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
opts.queryMap["scope_id"] = scopeId
req, err := c.client.NewRequest(ctx, "GET", "scopes", nil, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating List request: %w", err)
}
opts.queryMap["scope_id"] = scopeId
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
+2 -12
View File
@@ -16,7 +16,6 @@ type Option func(*options)
type options struct {
postMap map[string]interface{}
queryMap map[string]string
withScopeId string
withAutomaticVersioning bool
}
@@ -33,25 +32,16 @@ func getOpts(opt ...Option) (options, []api.Option) {
o(&opts)
}
var apiOpts []api.Option
if opts.withScopeId != "" {
apiOpts = append(apiOpts, api.WithScopeId(opts.withScopeId))
}
return opts, apiOpts
}
func WithScopeId(id string) Option {
return func(o *options) {
o.withScopeId = id
}
}
// If set, and if the version is zero during an update, the API will perform a
// fetch to get the current version of the resource and populate it during the
// update call. This is convenient but opens up the possibility for subtle
// order-of-modification issues, so use carefully.
func WithAutomaticVersioning() Option {
func WithAutomaticVersioning(enable bool) Option {
return func(o *options) {
o.withAutomaticVersioning = true
o.withAutomaticVersioning = enable
}
}
+13 -9
View File
@@ -29,20 +29,31 @@ type Target struct {
DefaultPort uint32 `json:"default_port,omitempty"`
}
// Client is a client for this collection
type Client struct {
client *api.Client
}
// Creates a new client for this collection. The submitted API client is cloned;
// modifications to it after generating this client will not have effect. If you
// need to make changes to the underlying API client, use ApiClient() to access
// it.
func NewClient(c *api.Client) *Client {
return &Client{client: c}
return &Client{client: c.Clone()}
}
// ApiClient returns the underlying API client
func (c *Client) ApiClient() *api.Client {
return c.client
}
func (c *Client) Create(ctx context.Context, resourceType string, scopeId string, opt ...Option) (*Target, *api.Error, error) {
if scopeId == "" {
return nil, nil, fmt.Errorf("empty scopeId value passed into Create request")
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
@@ -92,7 +103,6 @@ func (c *Client) Read(ctx context.Context, targetId string, opt ...Option) (*Tar
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
req, err := c.client.NewRequest(ctx, "GET", fmt.Sprintf("targets/%s", targetId), nil, apiOpts...)
if err != nil {
@@ -132,7 +142,6 @@ func (c *Client) Update(ctx context.Context, targetId string, version uint32, op
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
if version == 0 {
if !opts.withAutomaticVersioning {
@@ -191,7 +200,6 @@ func (c *Client) Delete(ctx context.Context, targetId string, opt ...Option) (bo
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
req, err := c.client.NewRequest(ctx, "DELETE", fmt.Sprintf("targets/%s", targetId), nil, apiOpts...)
if err != nil {
@@ -234,7 +242,6 @@ func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*Ta
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
opts.queryMap["scope_id"] = scopeId
req, err := c.client.NewRequest(ctx, "GET", "targets", nil, apiOpts...)
@@ -278,7 +285,6 @@ func (c *Client) AddHostSets(ctx context.Context, targetId string, version uint3
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
if version == 0 {
if !opts.withAutomaticVersioning {
@@ -341,7 +347,6 @@ func (c *Client) SetHostSets(ctx context.Context, targetId string, version uint3
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
if version == 0 {
if !opts.withAutomaticVersioning {
@@ -407,7 +412,6 @@ func (c *Client) RemoveHostSets(ctx context.Context, targetId string, version ui
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
if version == 0 {
if !opts.withAutomaticVersioning {
+7 -5
View File
@@ -24,18 +24,18 @@ func TestCustom(t *testing.T) {
token := tc.Token()
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
client := tc.Client().Clone()
client.SetScopeId(proj.GetPublicId())
client.SetToken(token.Token)
hc, apiErr, err := hostcatalogs.NewClient(client).Create(tc.Context(), "static")
hc, apiErr, err := hostcatalogs.NewClient(client).Create(tc.Context(), "static", proj.GetPublicId())
require.NoError(err)
require.Nil(apiErr)
hSetClient := hostsets.NewClient(client)
hSet, apiErr, err := hSetClient.Create2(tc.Context(), hc.Id)
hSet, apiErr, err := hSetClient.Create(tc.Context(), hc.Id)
require.NoError(err)
require.Nil(apiErr)
require.NotNil(hSet)
hSet2, apiErr, err := hSetClient.Create2(tc.Context(), hc.Id)
hSet2, apiErr, err := hSetClient.Create(tc.Context(), hc.Id)
require.NoError(err)
require.Nil(apiErr)
require.NotNil(hSet2)
@@ -73,8 +73,8 @@ func TestList(t *testing.T) {
client := tc.Client()
token := tc.Token()
client.SetToken(token.Token)
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
client.SetScopeId(proj.GetPublicId())
tarClient := targets.NewClient(client)
ul, apiErr, err := tarClient.List(tc.Context(), proj.GetPublicId())
@@ -129,6 +129,7 @@ func TestCrud(t *testing.T) {
client := tc.Client()
token := tc.Token()
client.SetToken(token.Token)
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
checkResource := func(t *testing.T, step string, h *targets.Target, apiErr *api.Error, err error, wantedName string, wantVersion uint32) {
@@ -175,6 +176,7 @@ func TestSet_Errors(t *testing.T) {
client := tc.Client()
token := tc.Token()
client.SetToken(token.Token)
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
tarClient := targets.NewClient(client)
+2 -12
View File
@@ -16,7 +16,6 @@ type Option func(*options)
type options struct {
postMap map[string]interface{}
queryMap map[string]string
withScopeId string
withAutomaticVersioning bool
}
@@ -33,25 +32,16 @@ func getOpts(opt ...Option) (options, []api.Option) {
o(&opts)
}
var apiOpts []api.Option
if opts.withScopeId != "" {
apiOpts = append(apiOpts, api.WithScopeId(opts.withScopeId))
}
return opts, apiOpts
}
func WithScopeId(id string) Option {
return func(o *options) {
o.withScopeId = id
}
}
// If set, and if the version is zero during an update, the API will perform a
// fetch to get the current version of the resource and populate it during the
// update call. This is convenient but opens up the possibility for subtle
// order-of-modification issues, so use carefully.
func WithAutomaticVersioning() Option {
func WithAutomaticVersioning(enable bool) Option {
return func(o *options) {
o.withAutomaticVersioning = true
o.withAutomaticVersioning = enable
}
}
+26 -6
View File
@@ -25,24 +25,42 @@ type User struct {
Version uint32 `json:"version,omitempty"`
}
// Client is a client for this collection
type Client struct {
client *api.Client
}
// Creates a new client for this collection. The submitted API client is cloned;
// modifications to it after generating this client will not have effect. If you
// need to make changes to the underlying API client, use ApiClient() to access
// it.
func NewClient(c *api.Client) *Client {
return &Client{client: c}
return &Client{client: c.Clone()}
}
func (c *Client) Create(ctx context.Context, opt ...Option) (*User, *api.Error, error) {
// ApiClient returns the underlying API client
func (c *Client) ApiClient() *api.Client {
return c.client
}
func (c *Client) Create(ctx context.Context, scopeId string, opt ...Option) (*User, *api.Error, error) {
if scopeId == "" {
return nil, nil, fmt.Errorf("empty scopeId value passed into Create request")
}
opts, apiOpts := getOpts(opt...)
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts.postMap["scope_id"] = scopeId
req, err := c.client.NewRequest(ctx, "POST", "users", opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Create request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
@@ -69,9 +87,8 @@ func (c *Client) Create(ctx context.Context, opt ...Option) (*User, *api.Error,
func (c *Client) Read(ctx context.Context, userId string, opt ...Option) (*User, *api.Error, error) {
if userId == "" {
return nil, nil, fmt.Errorf("empty userId value passed into Read request")
return nil, nil, fmt.Errorf("empty userId value passed into Read request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
@@ -169,7 +186,6 @@ func (c *Client) Delete(ctx context.Context, userId string, opt ...Option) (bool
if userId == "" {
return false, nil, fmt.Errorf("empty userId value passed into Delete request")
}
if c.client == nil {
return false, nil, fmt.Errorf("nil client")
}
@@ -208,12 +224,16 @@ func (c *Client) Delete(ctx context.Context, userId string, opt ...Option) (bool
return target.Existed, apiErr, nil
}
func (c *Client) List(ctx context.Context, opt ...Option) ([]*User, *api.Error, error) {
func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*User, *api.Error, error) {
if scopeId == "" {
return nil, nil, fmt.Errorf("empty scopeId value passed into List request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
opts.queryMap["scope_id"] = scopeId
req, err := c.client.NewRequest(ctx, "GET", "users", nil, apiOpts...)
if err != nil {
+23 -38
View File
@@ -13,23 +13,18 @@ import (
"github.com/stretchr/testify/require"
)
func TestUsers_List(t *testing.T) {
func TestList(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org := iam.TestOrg(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
org := iam.TestOrg(t, tc.IamRepo(), iam.WithUserId(token.UserId))
userClient := users.NewClient(client)
ul, apiErr, err := userClient.List(tc.Context())
ul, apiErr, err := userClient.List(tc.Context(), org.GetPublicId())
assert.NoError(err)
assert.Nil(apiErr)
assert.Empty(ul)
@@ -39,21 +34,21 @@ func TestUsers_List(t *testing.T) {
expected = append(expected, &users.User{Name: fmt.Sprint(i)})
}
expected[0], apiErr, err = userClient.Create(tc.Context(), users.WithName(expected[0].Name))
expected[0], apiErr, err = userClient.Create(tc.Context(), org.GetPublicId(), users.WithName(expected[0].Name))
assert.NoError(err)
assert.Nil(apiErr)
ul, apiErr, err = userClient.List(tc.Context())
ul, apiErr, err = userClient.List(tc.Context(), org.GetPublicId())
assert.NoError(err)
assert.Nil(apiErr)
assert.ElementsMatch(comparableSlice(expected[:1]), comparableSlice(ul))
for i := 1; i < 10; i++ {
expected[i], apiErr, err = userClient.Create(tc.Context(), users.WithName(expected[i].Name))
expected[i], apiErr, err = userClient.Create(tc.Context(), org.GetPublicId(), users.WithName(expected[i].Name))
assert.NoError(err)
assert.Nil(apiErr)
}
ul, apiErr, err = userClient.List(tc.Context())
ul, apiErr, err = userClient.List(tc.Context(), org.GetPublicId())
require.NoError(err)
assert.Nil(apiErr)
assert.ElementsMatch(comparableSlice(expected), comparableSlice(ul))
@@ -74,20 +69,15 @@ func comparableSlice(in []*users.User) []users.User {
return filtered
}
func TestUser_Crud(t *testing.T) {
func TestCrud(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org := iam.TestOrg(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
org := iam.TestOrg(t, tc.IamRepo(), iam.WithUserId(token.UserId))
userClient := users.NewClient(client)
checkUser := func(step string, u *users.User, apiErr *api.Error, err error, wantedName string, wantedVersion uint32) {
@@ -104,7 +94,7 @@ func TestUser_Crud(t *testing.T) {
assert.EqualValues(wantedVersion, u.Version)
}
u, apiErr, err := userClient.Create(tc.Context(), users.WithName("foo"))
u, apiErr, err := userClient.Create(tc.Context(), org.GetPublicId(), users.WithName("foo"))
checkUser("create", u, apiErr, err, "foo", 1)
u, apiErr, err = userClient.Read(tc.Context(), u.Id)
@@ -127,29 +117,24 @@ func TestUser_Crud(t *testing.T) {
assert.EqualValues(http.StatusForbidden, apiErr.Status)
}
func TestUser_Errors(t *testing.T) {
func TestErrors(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org := iam.TestOrg(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
org := iam.TestOrg(t, tc.IamRepo(), iam.WithUserId(token.UserId))
userClient := users.NewClient(client)
u, apiErr, err := userClient.Create(tc.Context(), users.WithName("first"))
u, apiErr, err := userClient.Create(tc.Context(), org.GetPublicId(), users.WithName("first"))
require.NoError(err)
assert.Nil(apiErr)
assert.NotNil(u)
// Create another resource with the same name.
_, apiErr, err = userClient.Create(tc.Context(), users.WithName("first"))
_, apiErr, err = userClient.Create(tc.Context(), org.GetPublicId(), users.WithName("first"))
require.NoError(err)
assert.NotNil(apiErr)