Revert "Revert "convert /buckets endpoint error to platform error ""

pull/10616/head
kelwang 2018-11-30 13:27:40 -05:00 committed by GitHub
parent e5a29ab446
commit 6db9acc951
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 366 additions and 236 deletions

View File

@ -29,10 +29,12 @@ func (c *Client) initializeBuckets(ctx context.Context, tx *bolt.Tx) error {
return nil
}
func (c *Client) setOrganizationOnBucket(ctx context.Context, tx *bolt.Tx, b *platform.Bucket) error {
func (c *Client) setOrganizationOnBucket(ctx context.Context, tx *bolt.Tx, b *platform.Bucket) *platform.Error {
o, err := c.findOrganizationByID(ctx, tx, b.OrganizationID)
if err != nil {
return err
return &platform.Error{
Err: err,
}
}
b.Organization = o.Name
return nil
@ -41,10 +43,13 @@ func (c *Client) setOrganizationOnBucket(ctx context.Context, tx *bolt.Tx, b *pl
// FindBucketByID retrieves a bucket by id.
func (c *Client) FindBucketByID(ctx context.Context, id platform.ID) (*platform.Bucket, error) {
var b *platform.Bucket
var err error
err := c.db.View(func(tx *bolt.Tx) error {
bkt, err := c.findBucketByID(ctx, tx, id)
if err != nil {
err = c.db.View(func(tx *bolt.Tx) error {
bkt, pe := c.findBucketByID(ctx, tx, id)
if pe != nil {
pe.Op = getOp(platform.OpFindBucketByID)
err = pe
return err
}
b = bkt
@ -58,26 +63,35 @@ func (c *Client) FindBucketByID(ctx context.Context, id platform.ID) (*platform.
return b, nil
}
func (c *Client) findBucketByID(ctx context.Context, tx *bolt.Tx, id platform.ID) (*platform.Bucket, error) {
func (c *Client) findBucketByID(ctx context.Context, tx *bolt.Tx, id platform.ID) (*platform.Bucket, *platform.Error) {
var b platform.Bucket
encodedID, err := id.Encode()
if err != nil {
return nil, err
return nil, &platform.Error{
Code: platform.EInvalid,
Err: err,
}
}
v := tx.Bucket(bucketBucket).Get(encodedID)
if len(v) == 0 {
// TODO: Make standard error
return nil, fmt.Errorf("bucket not found")
return nil, &platform.Error{
Code: platform.ENotFound,
Msg: "bucket not found",
}
}
if err := json.Unmarshal(v, &b); err != nil {
return nil, err
return nil, &platform.Error{
Err: err,
}
}
if err := c.setOrganizationOnBucket(ctx, tx, &b); err != nil {
return nil, err
return nil, &platform.Error{
Err: err,
}
}
return &b, nil
@ -87,10 +101,13 @@ func (c *Client) findBucketByID(ctx context.Context, tx *bolt.Tx, id platform.ID
// TODO: have method for finding bucket using organization name and bucket name.
func (c *Client) FindBucketByName(ctx context.Context, orgID platform.ID, n string) (*platform.Bucket, error) {
var b *platform.Bucket
var err error
err := c.db.View(func(tx *bolt.Tx) error {
bkt, err := c.findBucketByName(ctx, tx, orgID, n)
if err != nil {
err = c.db.View(func(tx *bolt.Tx) error {
bkt, pe := c.findBucketByName(ctx, tx, orgID, n)
if pe != nil {
pe.Op = getOp(platform.OpFindBucket)
err = pe
return err
}
b = bkt
@ -100,25 +117,32 @@ func (c *Client) FindBucketByName(ctx context.Context, orgID platform.ID, n stri
return b, err
}
func (c *Client) findBucketByName(ctx context.Context, tx *bolt.Tx, orgID platform.ID, n string) (*platform.Bucket, error) {
func (c *Client) findBucketByName(ctx context.Context, tx *bolt.Tx, orgID platform.ID, n string) (*platform.Bucket, *platform.Error) {
b := &platform.Bucket{
OrganizationID: orgID,
Name: n,
}
key, err := bucketIndexKey(b)
if err != nil {
return nil, err
return nil, &platform.Error{
Code: platform.EInvalid,
Err: err,
}
}
buf := tx.Bucket(bucketIndex).Get(key)
if buf == nil {
// TODO: Make standard error
return nil, fmt.Errorf("bucket not found")
return nil, &platform.Error{
Code: platform.ENotFound,
Msg: "bucket not found",
}
}
var id platform.ID
if err := id.Decode(buf); err != nil {
return nil, err
return nil, &platform.Error{
Err: err,
}
}
return c.findBucketByID(ctx, tx, id)
}
@ -127,16 +151,25 @@ func (c *Client) findBucketByName(ctx context.Context, tx *bolt.Tx, orgID platfo
// Filters using ID, or OrganizationID and bucket Name should be efficient.
// Other filters will do a linear scan across buckets until it finds a match.
func (c *Client) FindBucket(ctx context.Context, filter platform.BucketFilter) (*platform.Bucket, error) {
var b *platform.Bucket
var err error
if filter.ID != nil {
return c.FindBucketByID(ctx, *filter.ID)
b, err = c.FindBucketByID(ctx, *filter.ID)
if err != nil {
return nil, &platform.Error{
Op: getOp(platform.OpFindBucket),
Err: err,
}
}
return b, nil
}
if filter.Name != nil && filter.OrganizationID != nil {
return c.FindBucketByName(ctx, *filter.OrganizationID, *filter.Name)
}
var b *platform.Bucket
err := c.db.View(func(tx *bolt.Tx) error {
err = c.db.View(func(tx *bolt.Tx) error {
if filter.Organization != nil {
o, err := c.findOrganizationByName(ctx, tx, *filter.Organization)
if err != nil {
@ -156,11 +189,17 @@ func (c *Client) FindBucket(ctx context.Context, filter platform.BucketFilter) (
})
if err != nil {
return nil, err
return nil, &platform.Error{
Op: getOp(platform.OpFindBucket),
Err: err,
}
}
if b == nil {
return nil, fmt.Errorf("bucket not found")
return nil, &platform.Error{
Code: platform.ENotFound,
Msg: "bucket not found",
}
}
return b, nil
@ -233,12 +272,14 @@ func (c *Client) FindBuckets(ctx context.Context, filter platform.BucketFilter,
return bs, len(bs), nil
}
func (c *Client) findBuckets(ctx context.Context, tx *bolt.Tx, filter platform.BucketFilter) ([]*platform.Bucket, error) {
func (c *Client) findBuckets(ctx context.Context, tx *bolt.Tx, filter platform.BucketFilter) ([]*platform.Bucket, *platform.Error) {
bs := []*platform.Bucket{}
if filter.Organization != nil {
o, err := c.findOrganizationByName(ctx, tx, *filter.Organization)
if err != nil {
return nil, err
return nil, &platform.Error{
Err: err,
}
}
filter.OrganizationID = &o.ID
}
@ -252,7 +293,9 @@ func (c *Client) findBuckets(ctx context.Context, tx *bolt.Tx, filter platform.B
})
if err != nil {
return nil, err
return nil, &platform.Error{
Err: err,
}
}
return bs, nil
@ -260,6 +303,8 @@ func (c *Client) findBuckets(ctx context.Context, tx *bolt.Tx, filter platform.B
// CreateBucket creates a platform bucket and sets b.ID.
func (c *Client) CreateBucket(ctx context.Context, b *platform.Bucket) error {
var err error
op := getOp(platform.OpCreateBucket)
return c.db.Update(func(tx *bolt.Tx) error {
if !b.OrganizationID.Valid() {
o, err := c.findOrganizationByName(ctx, tx, b.Organization)
@ -273,37 +318,56 @@ func (c *Client) CreateBucket(ctx context.Context, b *platform.Bucket) error {
if !unique {
// TODO: make standard error
return fmt.Errorf("bucket with name %s already exists", b.Name)
return &platform.Error{
Code: platform.EConflict,
Op: op,
Msg: fmt.Sprintf("bucket with name %s already exists", b.Name),
}
}
b.ID = c.IDGenerator.ID()
if err := c.appendBucketEventToLog(ctx, tx, b.ID, bucketCreatedEvent); err != nil {
return err
if err = c.appendBucketEventToLog(ctx, tx, b.ID, bucketCreatedEvent); err != nil {
return &platform.Error{
Op: op,
Err: err,
}
}
if err := c.putBucket(ctx, tx, b); err != nil {
return err
if pe := c.putBucket(ctx, tx, b); pe != nil {
pe.Op = op
err = pe
}
return c.createBucketUserResourceMappings(ctx, tx, b)
if pe := c.createBucketUserResourceMappings(ctx, tx, b); pe != nil {
pe.Op = op
err = pe
}
return nil
})
}
// PutBucket will put a bucket without setting an ID.
func (c *Client) PutBucket(ctx context.Context, b *platform.Bucket) error {
return c.db.Update(func(tx *bolt.Tx) error {
return c.putBucket(ctx, tx, b)
var err error
pe := c.putBucket(ctx, tx, b)
if pe != nil {
err = pe
}
return err
})
}
func (c *Client) createBucketUserResourceMappings(ctx context.Context, tx *bolt.Tx, b *platform.Bucket) error {
func (c *Client) createBucketUserResourceMappings(ctx context.Context, tx *bolt.Tx, b *platform.Bucket) *platform.Error {
ms, err := c.findUserResourceMappings(ctx, tx, platform.UserResourceMappingFilter{
ResourceType: platform.OrgResourceType,
ResourceID: b.OrganizationID,
})
if err != nil {
return err
return &platform.Error{
Err: err,
}
}
for _, m := range ms {
@ -313,42 +377,55 @@ func (c *Client) createBucketUserResourceMappings(ctx context.Context, tx *bolt.
UserID: m.UserID,
UserType: m.UserType,
}); err != nil {
return err
return &platform.Error{
Err: err,
}
}
}
return nil
}
func (c *Client) putBucket(ctx context.Context, tx *bolt.Tx, b *platform.Bucket) error {
func (c *Client) putBucket(ctx context.Context, tx *bolt.Tx, b *platform.Bucket) *platform.Error {
b.Organization = ""
v, err := json.Marshal(b)
if err != nil {
return err
return &platform.Error{
Err: err,
}
}
encodedID, err := b.ID.Encode()
if err != nil {
return err
return &platform.Error{
Err: err,
}
}
key, err := bucketIndexKey(b)
key, pe := bucketIndexKey(b)
if err != nil {
return err
return pe
}
if err := tx.Bucket(bucketIndex).Put(key, encodedID); err != nil {
return err
return &platform.Error{
Err: err,
}
}
if err := tx.Bucket(bucketBucket).Put(encodedID, v); err != nil {
return err
return &platform.Error{
Err: err,
}
}
return c.setOrganizationOnBucket(ctx, tx, b)
}
func bucketIndexKey(b *platform.Bucket) ([]byte, error) {
func bucketIndexKey(b *platform.Bucket) ([]byte, *platform.Error) {
orgID, err := b.OrganizationID.Encode()
if err != nil {
return nil, err
return nil, &platform.Error{
Code: platform.EInvalid,
Err: err,
}
}
k := make([]byte, platform.IDLength+len(b.Name))
copy(k, orgID)
@ -439,34 +516,51 @@ func (c *Client) updateBucket(ctx context.Context, tx *bolt.Tx, id platform.ID,
// DeleteBucket deletes a bucket and prunes it from the index.
func (c *Client) DeleteBucket(ctx context.Context, id platform.ID) error {
return c.db.Update(func(tx *bolt.Tx) error {
return c.deleteBucket(ctx, tx, id)
var err error
if pe := c.deleteBucket(ctx, tx, id); pe != nil {
pe.Op = getOp(platform.OpDeleteBucket)
err = pe
}
return err
})
}
func (c *Client) deleteBucket(ctx context.Context, tx *bolt.Tx, id platform.ID) error {
b, err := c.findBucketByID(ctx, tx, id)
if err != nil {
return err
func (c *Client) deleteBucket(ctx context.Context, tx *bolt.Tx, id platform.ID) *platform.Error {
b, pe := c.findBucketByID(ctx, tx, id)
if pe != nil {
return pe
}
key, err := bucketIndexKey(b)
if err != nil {
return err
key, pe := bucketIndexKey(b)
if pe != nil {
return pe
}
// make lowercase deleteBucket with tx
if err := tx.Bucket(bucketIndex).Delete(key); err != nil {
return err
return &platform.Error{
Err: err,
}
}
encodedID, err := id.Encode()
if err != nil {
return err
return &platform.Error{
Code: platform.EInvalid,
Err: err,
}
}
if err := tx.Bucket(bucketBucket).Delete(encodedID); err != nil {
return err
return &platform.Error{
Err: err,
}
}
return c.deleteUserResourceMappings(ctx, tx, platform.UserResourceMappingFilter{
if err := c.deleteUserResourceMappings(ctx, tx, platform.UserResourceMappingFilter{
ResourceID: id,
ResourceType: platform.BucketResourceType,
})
}); err != nil {
return &platform.Error{
Err: err,
}
}
return nil
}
const bucketOperationLogKeyPrefix = "bucket"

View File

@ -5,10 +5,11 @@ import (
"testing"
"github.com/influxdata/platform"
"github.com/influxdata/platform/bolt"
platformtesting "github.com/influxdata/platform/testing"
)
func initBucketService(f platformtesting.BucketFields, t *testing.T) (platform.BucketService, func()) {
func initBucketService(f platformtesting.BucketFields, t *testing.T) (platform.BucketService, string, func()) {
c, closeFn, err := NewTestClient()
if err != nil {
t.Fatalf("failed to create new bolt client: %v", err)
@ -25,7 +26,7 @@ func initBucketService(f platformtesting.BucketFields, t *testing.T) (platform.B
t.Fatalf("failed to populate buckets")
}
}
return c, func() {
return c, bolt.OpPrefix, func() {
defer closeFn()
for _, o := range f.Organizations {
if err := c.DeleteOrganization(ctx, o.ID); err != nil {
@ -40,26 +41,6 @@ func initBucketService(f platformtesting.BucketFields, t *testing.T) (platform.B
}
}
func TestBucketService_CreateBucket(t *testing.T) {
platformtesting.CreateBucket(initBucketService, t)
}
func TestBucketService_FindBucketByID(t *testing.T) {
platformtesting.FindBucketByID(initBucketService, t)
}
func TestBucketService_FindBuckets(t *testing.T) {
platformtesting.FindBuckets(initBucketService, t)
}
func TestBucketService_DeleteBucket(t *testing.T) {
platformtesting.DeleteBucket(initBucketService, t)
}
func TestBucketService_FindBucket(t *testing.T) {
platformtesting.FindBucket(initBucketService, t)
}
func TestBucketService_UpdateBucket(t *testing.T) {
platformtesting.UpdateBucket(initBucketService, t)
func TestBucketService(t *testing.T) {
platformtesting.BucketService(initBucketService, t)
}

View File

@ -27,6 +27,16 @@ type Bucket struct {
RetentionPeriod time.Duration `json:"retentionPeriod"`
}
// ops for buckets error and buckets op logs.
var (
OpFindBucketByID = "FindBucketByID"
OpFindBucket = "FindBucket"
OpFindBuckets = "FindBuckets"
OpCreateBucket = "CreateBucket"
OpUpdateBucket = "UpdateBucket"
OpDeleteBucket = "DeleteBucket"
)
// BucketService represents a service for managing bucket data.
type BucketService interface {
// FindBucketByID returns a single bucket by ID.

View File

@ -66,8 +66,9 @@ func newBucketService(f Flags) (platform.BucketService, error) {
return c, nil
}
return &http.BucketService{
Addr: flags.host,
Token: flags.token,
Addr: flags.host,
Token: flags.token,
OpPrefix: bolt.OpPrefix,
}, nil
}

View File

@ -8,7 +8,6 @@ import (
"net/http"
"path"
"strconv"
"strings"
"time"
"github.com/influxdata/platform"
@ -268,10 +267,6 @@ func (h *BucketHandler) handleGetBucket(w http.ResponseWriter, r *http.Request)
b, err := h.BucketService.FindBucketByID(ctx, req.BucketID)
if err != nil {
// TODO(desa): fix this when using real errors library
if strings.Contains(err.Error(), "not found") {
err = errors.New(err.Error(), errors.NotFound)
}
EncodeError(ctx, err, w)
return
}
@ -315,10 +310,6 @@ func (h *BucketHandler) handleDeleteBucket(w http.ResponseWriter, r *http.Reques
}
if err := h.BucketService.DeleteBucket(ctx, req.BucketID); err != nil {
// TODO(desa): fix this when using real errors library
if strings.Contains(err.Error(), "not found") {
err = errors.New(err.Error(), errors.NotFound)
}
EncodeError(ctx, err, w)
return
}
@ -418,10 +409,6 @@ func (h *BucketHandler) handlePatchBucket(w http.ResponseWriter, r *http.Request
b, err := h.BucketService.UpdateBucket(ctx, req.BucketID, req.Update)
if err != nil {
// TODO(desa): fix this when using real errors library
if strings.Contains(err.Error(), "not found") {
err = errors.New(err.Error(), errors.NotFound)
}
EncodeError(ctx, err, w)
return
}
@ -474,6 +461,9 @@ type BucketService struct {
Addr string
Token string
InsecureSkipVerify bool
// OpPrefix is an additional property for error
// find bucket service, when finds nothing.
OpPrefix string
}
// FindBucketByID returns a single bucket by ID.
@ -495,7 +485,7 @@ func (s *BucketService) FindBucketByID(ctx context.Context, id platform.ID) (*pl
return nil, err
}
if err := CheckError(resp); err != nil {
if err := CheckError(resp, true); err != nil {
return nil, err
}
@ -515,7 +505,11 @@ func (s *BucketService) FindBucket(ctx context.Context, filter platform.BucketFi
}
if n == 0 {
return nil, ErrNotFound
return nil, &platform.Error{
Code: platform.ENotFound,
Op: s.OpPrefix + platform.OpFindBucket,
Err: ErrNotFound,
}
}
return bs[0], nil
@ -557,7 +551,7 @@ func (s *BucketService) FindBuckets(ctx context.Context, filter platform.BucketF
return nil, 0, err
}
if err := CheckError(resp); err != nil {
if err := CheckError(resp, true); err != nil {
return nil, 0, err
}
@ -608,7 +602,7 @@ func (s *BucketService) CreateBucket(ctx context.Context, b *platform.Bucket) er
}
// TODO(jsternberg): Should this check for a 201 explicitly?
if err := CheckError(resp); err != nil {
if err := CheckError(resp, true); err != nil {
return err
}
@ -654,7 +648,7 @@ func (s *BucketService) UpdateBucket(ctx context.Context, id platform.ID, upd pl
return nil, err
}
if err := CheckError(resp); err != nil {
if err := CheckError(resp, true); err != nil {
return nil, err
}
@ -684,7 +678,7 @@ func (s *BucketService) DeleteBucket(ctx context.Context, id platform.ID) error
if err != nil {
return err
}
return CheckError(resp)
return CheckError(resp, true)
}
func bucketIDPath(id platform.ID) string {

View File

@ -202,18 +202,18 @@ func TestService_handleGetBucket(t *testing.T) {
statusCode: http.StatusOK,
contentType: "application/json; charset=utf-8",
body: `
{
"links": {
"org": "/api/v2/orgs/020f755c3c082000",
"self": "/api/v2/buckets/020f755c3c082000",
"log": "/api/v2/buckets/020f755c3c082000/log"
},
"id": "020f755c3c082000",
"organizationID": "020f755c3c082000",
"name": "hello",
"retentionRules": [{"type": "expire", "everySeconds": 30}]
}
`,
{
"links": {
"org": "/api/v2/orgs/020f755c3c082000",
"self": "/api/v2/buckets/020f755c3c082000",
"log": "/api/v2/buckets/020f755c3c082000/log"
},
"id": "020f755c3c082000",
"organizationID": "020f755c3c082000",
"name": "hello",
"retentionRules": [{"type": "expire", "everySeconds": 30}]
}
`,
},
},
{
@ -221,7 +221,10 @@ func TestService_handleGetBucket(t *testing.T) {
fields: fields{
&mock.BucketService{
FindBucketByIDFn: func(ctx context.Context, id platform.ID) (*platform.Bucket, error) {
return nil, fmt.Errorf("bucket not found")
return nil, &platform.Error{
Code: platform.ENotFound,
Msg: "bucket not found",
}
},
},
},
@ -407,7 +410,10 @@ func TestService_handleDeleteBucket(t *testing.T) {
fields: fields{
&mock.BucketService{
DeleteBucketFn: func(ctx context.Context, id platform.ID) error {
return fmt.Errorf("bucket not found")
return &platform.Error{
Code: platform.ENotFound,
Msg: "bucket not found",
}
},
},
},
@ -535,7 +541,10 @@ func TestService_handlePatchBucket(t *testing.T) {
fields: fields{
&mock.BucketService{
UpdateBucketFn: func(ctx context.Context, id platform.ID, upd platform.BucketUpdate) (*platform.Bucket, error) {
return nil, fmt.Errorf("not found")
return nil, &platform.Error{
Code: platform.ENotFound,
Msg: "bucket not found",
}
},
},
},
@ -621,7 +630,10 @@ func TestService_handlePatchBucket(t *testing.T) {
return d, nil
}
return nil, fmt.Errorf("not found")
return nil, &platform.Error{
Code: platform.ENotFound,
Msg: "bucket not found",
}
},
},
},
@ -670,7 +682,10 @@ func TestService_handlePatchBucket(t *testing.T) {
return d, nil
}
return nil, fmt.Errorf("not found")
return nil, &platform.Error{
Code: platform.ENotFound,
Msg: "bucket not found",
}
},
},
},
@ -738,7 +753,7 @@ func TestService_handlePatchBucket(t *testing.T) {
}
}
func initBucketService(f platformtesting.BucketFields, t *testing.T) (platform.BucketService, func()) {
func initBucketService(f platformtesting.BucketFields, t *testing.T) (platform.BucketService, string, func()) {
svc := inmem.NewService()
svc.IDGenerator = f.IDGenerator
@ -759,11 +774,12 @@ func initBucketService(f platformtesting.BucketFields, t *testing.T) (platform.B
handler.BucketService = svc
server := httptest.NewServer(handler)
client := BucketService{
Addr: server.URL,
Addr: server.URL,
OpPrefix: inmem.OpPrefix,
}
done := server.Close
return &client, done
return &client, inmem.OpPrefix, done
}
func TestBucketService(t *testing.T) {

View File

@ -8,22 +8,30 @@ import (
)
var (
errBucketNotFound = fmt.Errorf("bucket not found")
errBucketNotFound = "bucket not found"
)
func (c *Service) loadBucket(ctx context.Context, id platform.ID) (*platform.Bucket, error) {
i, ok := c.bucketKV.Load(id.String())
func (s *Service) loadBucket(ctx context.Context, id platform.ID) (*platform.Bucket, *platform.Error) {
i, ok := s.bucketKV.Load(id.String())
if !ok {
return nil, errBucketNotFound
return nil, &platform.Error{
Code: platform.ENotFound,
Msg: errBucketNotFound,
}
}
b, ok := i.(platform.Bucket)
if !ok {
return nil, fmt.Errorf("type %T is not a bucket", i)
return nil, &platform.Error{
Code: platform.EInternal,
Msg: fmt.Sprintf("type %T is not a bucket", i),
}
}
if err := c.setOrganizationNameOnBucket(ctx, &b); err != nil {
return nil, err
if err := s.setOrganizationNameOnBucket(ctx, &b); err != nil {
return nil, &platform.Error{
Err: err,
}
}
return &b, nil
@ -41,7 +49,15 @@ func (c *Service) setOrganizationNameOnBucket(ctx context.Context, b *platform.B
// FindBucketByID returns a single bucket by ID.
func (s *Service) FindBucketByID(ctx context.Context, id platform.ID) (*platform.Bucket, error) {
return s.loadBucket(ctx, id)
var b *platform.Bucket
var pe *platform.Error
var err error
if b, pe = s.loadBucket(ctx, id); pe != nil {
pe.Op = OpPrefix + platform.OpFindBucketByID
err = pe
}
return b, err
}
func (c *Service) forEachBucket(ctx context.Context, fn func(b *platform.Bucket) bool) error {
@ -76,13 +92,28 @@ func (s *Service) filterBuckets(ctx context.Context, fn func(b *platform.Bucket)
// FindBucket returns the first bucket that matches filter.
func (s *Service) FindBucket(ctx context.Context, filter platform.BucketFilter) (*platform.Bucket, error) {
op := OpPrefix + platform.OpFindBucket
var err error
var b *platform.Bucket
if filter.ID == nil && filter.Name == nil && filter.OrganizationID == nil {
return nil, fmt.Errorf("no filter parameters provided")
return nil, &platform.Error{
Code: platform.EInvalid,
Op: op,
Msg: "no filter parameters provided",
}
}
// filter by bucket id
if filter.ID != nil {
return s.FindBucketByID(ctx, *filter.ID)
b, err = s.FindBucketByID(ctx, *filter.ID)
if err != nil {
return nil, &platform.Error{
Op: op,
Err: err,
}
}
return b, nil
}
bs, n, err := s.FindBuckets(ctx, filter)
@ -91,18 +122,24 @@ func (s *Service) FindBucket(ctx context.Context, filter platform.BucketFilter)
}
if n < 1 {
return nil, fmt.Errorf("bucket not found")
return nil, &platform.Error{
Code: platform.ENotFound,
Op: op,
Msg: "bucket not found",
}
}
return bs[0], nil
}
func (s *Service) findBuckets(ctx context.Context, filter platform.BucketFilter, opt ...platform.FindOptions) ([]*platform.Bucket, error) {
func (s *Service) findBuckets(ctx context.Context, filter platform.BucketFilter, opt ...platform.FindOptions) ([]*platform.Bucket, *platform.Error) {
// filter by bucket id
if filter.ID != nil {
b, err := s.FindBucketByID(ctx, *filter.ID)
if err != nil {
return nil, err
return nil, &platform.Error{
Err: err,
}
}
return []*platform.Bucket{b}, nil
@ -111,7 +148,9 @@ func (s *Service) findBuckets(ctx context.Context, filter platform.BucketFilter,
if filter.Organization != nil {
o, err := s.findOrganizationByName(ctx, *filter.Organization)
if err != nil {
return nil, err
return nil, &platform.Error{
Err: err,
}
}
filter.OrganizationID = &o.ID
}
@ -136,7 +175,9 @@ func (s *Service) findBuckets(ctx context.Context, filter platform.BucketFilter,
bs, err := s.filterBuckets(ctx, filterFunc)
if err != nil {
return nil, err
return nil, &platform.Error{
Err: err,
}
}
return bs, nil
}
@ -144,8 +185,11 @@ func (s *Service) findBuckets(ctx context.Context, filter platform.BucketFilter,
// FindBuckets returns a list of buckets that match filter and the total count of matching buckets.
// Additional options provide pagination & sorting.
func (s *Service) FindBuckets(ctx context.Context, filter platform.BucketFilter, opt ...platform.FindOptions) ([]*platform.Bucket, int, error) {
bs, err := s.findBuckets(ctx, filter, opt...)
if err != nil {
var err error
bs, pe := s.findBuckets(ctx, filter, opt...)
if pe != nil {
pe.Op = OpPrefix + platform.OpFindBuckets
err = pe
return nil, 0, err
}
for _, b := range bs {
@ -170,7 +214,11 @@ func (s *Service) CreateBucket(ctx context.Context, b *platform.Bucket) error {
OrganizationID: &b.OrganizationID,
}
if _, err := s.FindBucket(ctx, filter); err == nil {
return fmt.Errorf("bucket with name %s already exists", b.Name)
return &platform.Error{
Code: platform.EConflict,
Op: OpPrefix + platform.OpCreateBucket,
Msg: fmt.Sprintf("bucket with name %s already exists", b.Name),
}
}
b.ID = s.IDGenerator.ID()
return s.PutBucket(ctx, b)
@ -187,7 +235,10 @@ func (s *Service) PutBucket(ctx context.Context, b *platform.Bucket) error {
func (s *Service) UpdateBucket(ctx context.Context, id platform.ID, upd platform.BucketUpdate) (*platform.Bucket, error) {
b, err := s.FindBucketByID(ctx, id)
if err != nil {
return nil, err
return nil, &platform.Error{
Op: OpPrefix + platform.OpUpdateBucket,
Err: err,
}
}
if upd.Name != nil {
@ -206,7 +257,10 @@ func (s *Service) UpdateBucket(ctx context.Context, id platform.ID, upd platform
// DeleteBucket removes a bucket by ID.
func (s *Service) DeleteBucket(ctx context.Context, id platform.ID) error {
if _, err := s.FindBucketByID(ctx, id); err != nil {
return err
return &platform.Error{
Op: OpPrefix + platform.OpDeleteBucket,
Err: err,
}
}
s.bucketKV.Delete(id.String())
return nil

View File

@ -8,7 +8,7 @@ import (
platformtesting "github.com/influxdata/platform/testing"
)
func initBucketService(f platformtesting.BucketFields, t *testing.T) (platform.BucketService, func()) {
func initBucketService(f platformtesting.BucketFields, t *testing.T) (platform.BucketService, string, func()) {
s := NewService()
s.IDGenerator = f.IDGenerator
ctx := context.Background()
@ -22,29 +22,9 @@ func initBucketService(f platformtesting.BucketFields, t *testing.T) (platform.B
t.Fatalf("failed to populate buckets")
}
}
return s, func() {}
return s, OpPrefix, func() {}
}
func TestBucketService_CreateBucket(t *testing.T) {
platformtesting.CreateBucket(initBucketService, t)
}
func TestBucketService_FindBucketByID(t *testing.T) {
platformtesting.FindBucketByID(initBucketService, t)
}
func TestBucketService_FindBuckets(t *testing.T) {
platformtesting.FindBuckets(initBucketService, t)
}
func TestBucketService_DeleteBucket(t *testing.T) {
platformtesting.DeleteBucket(initBucketService, t)
}
func TestBucketService_FindBucket(t *testing.T) {
platformtesting.FindBucket(initBucketService, t)
}
func TestBucketService_UpdateBucket(t *testing.T) {
platformtesting.UpdateBucket(initBucketService, t)
func TestBucketService(t *testing.T) {
platformtesting.BucketService(initBucketService, t)
}

View File

@ -40,13 +40,13 @@ type BucketFields struct {
}
type bucketServiceF func(
init func(BucketFields, *testing.T) (platform.BucketService, func()),
init func(BucketFields, *testing.T) (platform.BucketService, string, func()),
t *testing.T,
)
// BucketService tests all the service functions.
func BucketService(
init func(BucketFields, *testing.T) (platform.BucketService, func()),
init func(BucketFields, *testing.T) (platform.BucketService, string, func()),
t *testing.T,
) {
tests := []struct {
@ -87,7 +87,7 @@ func BucketService(
// CreateBucket testing
func CreateBucket(
init func(BucketFields, *testing.T) (platform.BucketService, func()),
init func(BucketFields, *testing.T) (platform.BucketService, string, func()),
t *testing.T,
) {
type args struct {
@ -272,7 +272,11 @@ func CreateBucket(
OrganizationID: MustIDBase16(orgOneID),
},
},
err: fmt.Errorf("bucket with name bucket1 already exists"),
err: &platform.Error{
Code: platform.EConflict,
Op: platform.OpCreateBucket,
Msg: fmt.Sprintf("bucket with name bucket1 already exists"),
},
},
},
{
@ -328,22 +332,11 @@ func CreateBucket(
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s, done := init(tt.fields, t)
s, opPrefix, done := init(tt.fields, t)
defer done()
ctx := context.TODO()
err := s.CreateBucket(ctx, tt.args.bucket)
if (err != nil) != (tt.wants.err != nil) {
t.Fatalf("expected error '%v' got '%v'", tt.wants.err, err)
}
if tt.wants.err == nil && !tt.args.bucket.ID.Valid() {
t.Fatalf("bucket ID not set from CreateBucket")
}
if err != nil && tt.wants.err != nil {
if err.Error() != tt.wants.err.Error() {
t.Fatalf("expected error messages to match '%v' got '%v'", tt.wants.err, err.Error())
}
}
diffPlatformErrors(tt.name, err, tt.wants.err, opPrefix, t)
// Delete only newly created buckets - ie., with a not nil ID
// if tt.args.bucket.ID.Valid() {
@ -363,7 +356,7 @@ func CreateBucket(
// FindBucketByID testing
func FindBucketByID(
init func(BucketFields, *testing.T) (platform.BucketService, func()),
init func(BucketFields, *testing.T) (platform.BucketService, string, func()),
t *testing.T,
) {
type args struct {
@ -414,24 +407,49 @@ func FindBucketByID(
},
},
},
{
name: "find bucket by id not exist",
fields: BucketFields{
Buckets: []*platform.Bucket{
{
ID: MustIDBase16(bucketOneID),
OrganizationID: MustIDBase16(orgOneID),
Name: "bucket1",
},
{
ID: MustIDBase16(bucketTwoID),
OrganizationID: MustIDBase16(orgOneID),
Name: "bucket2",
},
},
Organizations: []*platform.Organization{
{
Name: "theorg",
ID: MustIDBase16(orgOneID),
},
},
},
args: args{
id: MustIDBase16(threeID),
},
wants: wants{
err: &platform.Error{
Code: platform.ENotFound,
Op: platform.OpFindBucketByID,
Msg: "bucket not found",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s, done := init(tt.fields, t)
s, opPrefix, done := init(tt.fields, t)
defer done()
ctx := context.TODO()
bucket, err := s.FindBucketByID(ctx, tt.args.id)
if (err != nil) != (tt.wants.err != nil) {
t.Fatalf("expected errors to be equal '%v' got '%v'", tt.wants.err, err)
}
if err != nil && tt.wants.err != nil {
if err.Error() != tt.wants.err.Error() {
t.Fatalf("expected error '%v' got '%v'", tt.wants.err, err)
}
}
diffPlatformErrors(tt.name, err, tt.wants.err, opPrefix, t)
if diff := cmp.Diff(bucket, tt.wants.bucket, bucketCmpOptions...); diff != "" {
t.Errorf("bucket is different -got/+want\ndiff %s", diff)
@ -442,7 +460,7 @@ func FindBucketByID(
// FindBuckets testing
func FindBuckets(
init func(BucketFields, *testing.T) (platform.BucketService, func()),
init func(BucketFields, *testing.T) (platform.BucketService, string, func()),
t *testing.T,
) {
type args struct {
@ -700,7 +718,7 @@ func FindBuckets(
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s, done := init(tt.fields, t)
s, opPrefix, done := init(tt.fields, t)
defer done()
ctx := context.TODO()
@ -719,15 +737,7 @@ func FindBuckets(
}
buckets, _, err := s.FindBuckets(ctx, filter)
if (err != nil) != (tt.wants.err != nil) {
t.Fatalf("expected errors to be equal '%v' got '%v'", tt.wants.err, err)
}
if err != nil && tt.wants.err != nil {
if err.Error() != tt.wants.err.Error() {
t.Fatalf("expected error '%v' got '%v'", tt.wants.err, err)
}
}
diffPlatformErrors(tt.name, err, tt.wants.err, opPrefix, t)
if diff := cmp.Diff(buckets, tt.wants.buckets, bucketCmpOptions...); diff != "" {
t.Errorf("buckets are different -got/+want\ndiff %s", diff)
@ -738,7 +748,7 @@ func FindBuckets(
// DeleteBucket testing
func DeleteBucket(
init func(BucketFields, *testing.T) (platform.BucketService, func()),
init func(BucketFields, *testing.T) (platform.BucketService, string, func()),
t *testing.T,
) {
type args struct {
@ -817,7 +827,11 @@ func DeleteBucket(
ID: "1234567890654321",
},
wants: wants{
err: fmt.Errorf("bucket not found"),
err: &platform.Error{
Op: platform.OpDeleteBucket,
Msg: "bucket not found",
Code: platform.ENotFound,
},
buckets: []*platform.Bucket{
{
Name: "A",
@ -838,19 +852,11 @@ func DeleteBucket(
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s, done := init(tt.fields, t)
s, opPrefix, done := init(tt.fields, t)
defer done()
ctx := context.TODO()
err := s.DeleteBucket(ctx, MustIDBase16(tt.args.ID))
if (err != nil) != (tt.wants.err != nil) {
t.Fatalf("expected error '%v' got '%v'", tt.wants.err, err)
}
if err != nil && tt.wants.err != nil {
if err.Error() != tt.wants.err.Error() {
t.Fatalf("expected error messages to match '%v' got '%v'", tt.wants.err, err.Error())
}
}
diffPlatformErrors(tt.name, err, tt.wants.err, opPrefix, t)
filter := platform.BucketFilter{}
buckets, _, err := s.FindBuckets(ctx, filter)
@ -866,7 +872,7 @@ func DeleteBucket(
// FindBucket testing
func FindBucket(
init func(BucketFields, *testing.T) (platform.BucketService, func()),
init func(BucketFields, *testing.T) (platform.BucketService, string, func()),
t *testing.T,
) {
type args struct {
@ -936,14 +942,18 @@ func FindBucket(
organizationID: MustIDBase16(orgOneID),
},
wants: wants{
err: fmt.Errorf("no results found"),
err: &platform.Error{
Code: platform.ENotFound,
Op: platform.OpFindBucket,
Msg: "no results found",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s, done := init(tt.fields, t)
s, opPrefix, done := init(tt.fields, t)
defer done()
ctx := context.TODO()
filter := platform.BucketFilter{}
@ -955,9 +965,7 @@ func FindBucket(
}
bucket, err := s.FindBucket(ctx, filter)
if (err != nil) != (tt.wants.err != nil) {
t.Fatalf("expected error '%v' got '%v'", tt.wants.err, err)
}
diffPlatformErrors(tt.name, err, tt.wants.err, opPrefix, t)
if diff := cmp.Diff(bucket, tt.wants.bucket, bucketCmpOptions...); diff != "" {
t.Errorf("buckets are different -got/+want\ndiff %s", diff)
@ -968,7 +976,7 @@ func FindBucket(
// UpdateBucket testing
func UpdateBucket(
init func(BucketFields, *testing.T) (platform.BucketService, func()),
init func(BucketFields, *testing.T) (platform.BucketService, string, func()),
t *testing.T,
) {
type args struct {
@ -1099,7 +1107,7 @@ func UpdateBucket(
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s, done := init(tt.fields, t)
s, opPrefix, done := init(tt.fields, t)
defer done()
ctx := context.TODO()
@ -1113,15 +1121,7 @@ func UpdateBucket(
}
bucket, err := s.UpdateBucket(ctx, tt.args.id, upd)
if (err != nil) != (tt.wants.err != nil) {
t.Fatalf("expected error '%v' got '%v'", tt.wants.err, err)
}
if err != nil && tt.wants.err != nil {
if err.Error() != tt.wants.err.Error() {
t.Fatalf("expected error messages to match '%v' got '%v'", tt.wants.err, err.Error())
}
}
diffPlatformErrors(tt.name, err, tt.wants.err, opPrefix, t)
if diff := cmp.Diff(bucket, tt.wants.bucket, bucketCmpOptions...); diff != "" {
t.Errorf("bucket is different -got/+want\ndiff %s", diff)