Merge pull request #2054 from influxdata/convert_view_errors

Convert view errors
pull/10616/head
kelwang 2018-12-20 12:41:22 -05:00 committed by GitHub
commit 5797324cfc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 327 additions and 160 deletions

View File

@ -219,12 +219,12 @@ func (c *Client) CreateDashboard(ctx context.Context, d *platform.Dashboard) err
return nil
}
func (c *Client) createViewIfNotExists(ctx context.Context, tx *bolt.Tx, cell *platform.Cell, opts platform.AddDashboardCellOptions) error {
func (c *Client) createViewIfNotExists(ctx context.Context, tx *bolt.Tx, cell *platform.Cell, opts platform.AddDashboardCellOptions) *platform.Error {
if opts.UsingView.Valid() {
// Creates a hard copy of a view
v, err := c.findViewByID(ctx, tx, opts.UsingView)
if err != nil {
return err
v, pe := c.findViewByID(ctx, tx, opts.UsingView)
if pe != nil {
return pe
}
view, err := c.copyView(ctx, tx, v.ID)
if err != nil {

View File

@ -27,43 +27,49 @@ func (c *Client) FindViewByID(ctx context.Context, id platform.ID) (*platform.Vi
err := c.db.View(func(tx *bolt.Tx) error {
dash, err := c.findViewByID(ctx, tx, id)
if err != nil {
return err
return &platform.Error{
Err: err,
Op: getOp(platform.OpFindViewByID),
}
}
d = dash
return nil
})
if err != nil {
return nil, err
}
return d, nil
return d, err
}
func (c *Client) findViewByID(ctx context.Context, tx *bolt.Tx, id platform.ID) (*platform.View, error) {
func (c *Client) findViewByID(ctx context.Context, tx *bolt.Tx, id platform.ID) (*platform.View, *platform.Error) {
var d platform.View
encodedID, err := id.Encode()
if err != nil {
return nil, err
return nil, &platform.Error{
Err: err,
}
}
v := tx.Bucket(viewBucket).Get(encodedID)
if len(v) == 0 {
return nil, platform.ErrViewNotFound
return nil, &platform.Error{
Code: platform.ENotFound,
Msg: platform.ErrViewNotFound,
}
}
if err := json.Unmarshal(v, &d); err != nil {
return nil, err
return nil, &platform.Error{
Err: err,
}
}
return &d, nil
}
func (c *Client) copyView(ctx context.Context, tx *bolt.Tx, id platform.ID) (*platform.View, error) {
v, err := c.findViewByID(ctx, tx, id)
if err != nil {
return nil, err
func (c *Client) copyView(ctx context.Context, tx *bolt.Tx, id platform.ID) (*platform.View, *platform.Error) {
v, pe := c.findViewByID(ctx, tx, id)
if pe != nil {
return nil, pe
}
view := &platform.View{
@ -73,8 +79,8 @@ func (c *Client) copyView(ctx context.Context, tx *bolt.Tx, id platform.ID) (*pl
Properties: v.Properties,
}
if err := c.createView(ctx, tx, view); err != nil {
return nil, err
if pe := c.createView(ctx, tx, view); pe != nil {
return nil, pe
}
return view, nil
@ -99,11 +105,16 @@ func (c *Client) FindView(ctx context.Context, filter platform.ViewFilter) (*pla
})
if err != nil {
return nil, err
return nil, &platform.Error{
Err: err,
}
}
if d == nil {
return nil, platform.ErrViewNotFound
return nil, &platform.Error{
Code: platform.ENotFound,
Msg: platform.ErrViewNotFound,
}
}
return d, nil
@ -132,30 +143,36 @@ func filterViewsFn(filter platform.ViewFilter) func(v *platform.View) bool {
// FindViews retrives all views that match an arbitrary view filter.
func (c *Client) FindViews(ctx context.Context, filter platform.ViewFilter) ([]*platform.View, int, error) {
ds := []*platform.View{}
op := getOp(platform.OpFindViews)
if filter.ID != nil {
d, err := c.FindViewByID(ctx, *filter.ID)
if err != nil {
return nil, 0, err
if err != nil && platform.ErrorCode(err) != platform.ENotFound {
return nil, 0, &platform.Error{
Err: err,
Op: op,
}
}
if d != nil {
ds = append(ds, d)
}
return []*platform.View{d}, 1, nil
return ds, 1, nil
}
ds := []*platform.View{}
err := c.db.View(func(tx *bolt.Tx) error {
dashs, err := c.findViews(ctx, tx, filter)
if err != nil {
return err
return &platform.Error{
Err: err,
Op: op,
}
}
ds = dashs
return nil
})
if err != nil {
return nil, 0, err
}
return ds, len(ds), nil
return ds, len(ds), err
}
func (c *Client) findViews(ctx context.Context, tx *bolt.Tx, filter platform.ViewFilter) ([]*platform.View, error) {
@ -179,11 +196,17 @@ func (c *Client) findViews(ctx context.Context, tx *bolt.Tx, filter platform.Vie
// CreateView creates a platform view and sets d.ID.
func (c *Client) CreateView(ctx context.Context, d *platform.View) error {
return c.db.Update(func(tx *bolt.Tx) error {
return c.createView(ctx, tx, d)
if pe := c.createView(ctx, tx, d); pe != nil {
return &platform.Error{
Op: getOp(platform.OpCreateView),
Err: pe,
}
}
return nil
})
}
func (c *Client) createView(ctx context.Context, tx *bolt.Tx, d *platform.View) error {
func (c *Client) createView(ctx context.Context, tx *bolt.Tx, d *platform.View) *platform.Error {
d.ID = c.IDGenerator.ID()
return c.putView(ctx, tx, d)
}
@ -191,21 +214,30 @@ func (c *Client) createView(ctx context.Context, tx *bolt.Tx, d *platform.View)
// PutView will put a view without setting an ID.
func (c *Client) PutView(ctx context.Context, d *platform.View) error {
return c.db.Update(func(tx *bolt.Tx) error {
return c.putView(ctx, tx, d)
if pe := c.putView(ctx, tx, d); pe != nil {
return pe
}
return nil
})
}
func (c *Client) putView(ctx context.Context, tx *bolt.Tx, d *platform.View) error {
func (c *Client) putView(ctx context.Context, tx *bolt.Tx, d *platform.View) *platform.Error {
v, err := json.Marshal(d)
if err != nil {
return err
return &platform.Error{
Err: err,
}
}
encodedID, err := d.ID.Encode()
if err != nil {
return err
return &platform.Error{
Err: err,
}
}
if err := tx.Bucket(viewBucket).Put(encodedID, v); err != nil {
return err
return &platform.Error{
Err: err,
}
}
return nil
}
@ -230,9 +262,12 @@ func (c *Client) forEachView(ctx context.Context, tx *bolt.Tx, fn func(*platform
func (c *Client) UpdateView(ctx context.Context, id platform.ID, upd platform.ViewUpdate) (*platform.View, error) {
var d *platform.View
err := c.db.Update(func(tx *bolt.Tx) error {
dash, err := c.updateView(ctx, tx, id, upd)
if err != nil {
return err
dash, pe := c.updateView(ctx, tx, id, upd)
if pe != nil {
return &platform.Error{
Err: pe,
Op: getOp(platform.OpUpdateView),
}
}
d = dash
return nil
@ -265,24 +300,39 @@ func (c *Client) updateView(ctx context.Context, tx *bolt.Tx, id platform.ID, up
// DeleteView deletes a view and prunes it from the index.
func (c *Client) DeleteView(ctx context.Context, id platform.ID) error {
return c.db.Update(func(tx *bolt.Tx) error {
return c.deleteView(ctx, tx, id)
if pe := c.deleteView(ctx, tx, id); pe != nil {
return &platform.Error{
Err: pe,
Op: getOp(platform.OpDeleteView),
}
}
return nil
})
}
func (c *Client) deleteView(ctx context.Context, tx *bolt.Tx, id platform.ID) error {
_, err := c.findViewByID(ctx, tx, id)
if err != nil {
return err
func (c *Client) deleteView(ctx context.Context, tx *bolt.Tx, id platform.ID) *platform.Error {
_, pe := c.findViewByID(ctx, tx, id)
if pe != nil {
return pe
}
encodedID, err := id.Encode()
if err != nil {
return err
return &platform.Error{
Err: err,
}
}
if err := tx.Bucket(viewBucket).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.ViewResourceType,
})
}); err != nil {
return &platform.Error{
Err: err,
}
}
return nil
}

View File

@ -5,10 +5,11 @@ import (
"testing"
"github.com/influxdata/platform"
"github.com/influxdata/platform/bolt"
platformtesting "github.com/influxdata/platform/testing"
)
func initViewService(f platformtesting.ViewFields, t *testing.T) (platform.ViewService, func()) {
func initViewService(f platformtesting.ViewFields, t *testing.T) (platform.ViewService, string, func()) {
c, closeFn, err := NewTestClient()
if err != nil {
t.Fatalf("failed to create new bolt client: %v", err)
@ -20,7 +21,7 @@ func initViewService(f platformtesting.ViewFields, t *testing.T) (platform.ViewS
t.Fatalf("failed to populate cells")
}
}
return c, func() {
return c, bolt.OpPrefix, func() {
defer closeFn()
for _, b := range f.Views {
if err := c.DeleteView(ctx, b.ID); err != nil {

View File

@ -129,9 +129,6 @@ func (h *TelegrafHandler) handleGetTelegrafs(w http.ResponseWriter, r *http.Requ
}
tcs, _, err := h.TelegrafService.FindTelegrafConfigs(ctx, *filter)
if err != nil {
if err == platform.ErrViewNotFound {
err = errors.New(err.Error(), errors.NotFound)
}
EncodeError(ctx, err, w)
return
}
@ -150,9 +147,6 @@ func (h *TelegrafHandler) handleGetTelegraf(w http.ResponseWriter, r *http.Reque
}
tc, err := h.TelegrafService.FindTelegrafConfigByID(ctx, id)
if err != nil {
if err == platform.ErrViewNotFound {
err = errors.New(err.Error(), errors.NotFound)
}
EncodeError(ctx, err, w)
return
}

View File

@ -7,7 +7,6 @@ import (
"net/http"
"github.com/influxdata/platform"
"github.com/influxdata/platform/kit/errors"
"github.com/julienschmidt/httprouter"
)
@ -106,7 +105,7 @@ func (h *ViewHandler) handleGetViews(w http.ResponseWriter, r *http.Request) {
views, _, err := h.ViewService.FindViews(ctx, req.filter)
if err != nil {
EncodeError(ctx, errors.InternalErrorf("Error loading views: %v", err), w)
EncodeError(ctx, err, w)
return
}
@ -164,7 +163,7 @@ func (h *ViewHandler) handlePostViews(w http.ResponseWriter, r *http.Request) {
return
}
if err := h.ViewService.CreateView(ctx, req.View); err != nil {
EncodeError(ctx, errors.InternalErrorf("Error loading views: %v", err), w)
EncodeError(ctx, err, w)
return
}
@ -200,9 +199,6 @@ func (h *ViewHandler) handleGetView(w http.ResponseWriter, r *http.Request) {
view, err := h.ViewService.FindViewByID(ctx, req.ViewID)
if err != nil {
if err == platform.ErrViewNotFound {
err = errors.New(err.Error(), errors.NotFound)
}
EncodeError(ctx, err, w)
return
}
@ -221,7 +217,10 @@ func decodeGetViewRequest(ctx context.Context, r *http.Request) (*getViewRequest
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, errors.InvalidDataf("url missing id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
@ -245,9 +244,6 @@ func (h *ViewHandler) handleDeleteView(w http.ResponseWriter, r *http.Request) {
}
if err := h.ViewService.DeleteView(ctx, req.ViewID); err != nil {
if err == platform.ErrViewNotFound {
err = errors.New(err.Error(), errors.NotFound)
}
EncodeError(ctx, err, w)
return
}
@ -263,7 +259,10 @@ func decodeDeleteViewRequest(ctx context.Context, r *http.Request) (*deleteViewR
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, errors.InvalidDataf("url missing id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
@ -280,16 +279,13 @@ func decodeDeleteViewRequest(ctx context.Context, r *http.Request) (*deleteViewR
func (h *ViewHandler) handlePatchView(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
req, err := decodePatchViewRequest(ctx, r)
if err != nil {
EncodeError(ctx, err, w)
req, pe := decodePatchViewRequest(ctx, r)
if pe != nil {
EncodeError(ctx, pe, w)
return
}
view, err := h.ViewService.UpdateView(ctx, req.ViewID, req.Upd)
if err != nil {
if err == platform.ErrViewNotFound {
err = errors.New(err.Error(), errors.NotFound)
}
EncodeError(ctx, err, w)
return
}
@ -305,11 +301,13 @@ type patchViewRequest struct {
Upd platform.ViewUpdate
}
func decodePatchViewRequest(ctx context.Context, r *http.Request) (*patchViewRequest, error) {
func decodePatchViewRequest(ctx context.Context, r *http.Request) (*patchViewRequest, *platform.Error) {
req := &patchViewRequest{}
upd := platform.ViewUpdate{}
if err := json.NewDecoder(r.Body).Decode(&upd); err != nil {
return nil, errors.MalformedDataf(err.Error())
return nil, &platform.Error{
Err: err,
}
}
req.Upd = upd
@ -317,26 +315,36 @@ func decodePatchViewRequest(ctx context.Context, r *http.Request) (*patchViewReq
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, errors.InvalidDataf("url missing id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
if err := i.DecodeFromString(id); err != nil {
return nil, err
return nil, &platform.Error{
Err: err,
}
}
req.ViewID = i
if err := req.Valid(); err != nil {
return nil, errors.MalformedDataf(err.Error())
return nil, &platform.Error{
Err: err,
}
}
return req, nil
}
// Valid validates that the view ID is non zero valued and update has expected values set.
func (r *patchViewRequest) Valid() error {
func (r *patchViewRequest) Valid() *platform.Error {
if !r.ViewID.Valid() {
return fmt.Errorf("missing view ID")
return &platform.Error{
Code: platform.EInvalid,
Msg: "missing view ID",
}
}
return r.Upd.Valid()

View File

@ -222,7 +222,10 @@ func TestService_handleGetView(t *testing.T) {
fields: fields{
&mock.ViewService{
FindViewByIDF: func(ctx context.Context, id platform.ID) (*platform.View, error) {
return nil, platform.ErrViewNotFound
return nil, &platform.Error{
Code: platform.ENotFound,
Msg: platform.ErrViewNotFound,
}
},
},
},
@ -416,7 +419,10 @@ func TestService_handleDeleteView(t *testing.T) {
fields: fields{
&mock.ViewService{
DeleteViewF: func(ctx context.Context, id platform.ID) error {
return platform.ErrViewNotFound
return &platform.Error{
Code: platform.ENotFound,
Msg: platform.ErrViewNotFound,
}
},
},
},
@ -571,7 +577,10 @@ func TestService_handlePatchView(t *testing.T) {
fields: fields{
&mock.ViewService{
UpdateViewF: func(ctx context.Context, id platform.ID, upd platform.ViewUpdate) (*platform.View, error) {
return nil, platform.ErrViewNotFound
return nil, &platform.Error{
Code: platform.ENotFound,
Msg: platform.ErrViewNotFound,
}
},
},
},

View File

@ -7,22 +7,35 @@ import (
"github.com/influxdata/platform"
)
func (s *Service) loadView(ctx context.Context, id platform.ID) (*platform.View, error) {
func (s *Service) loadView(ctx context.Context, id platform.ID) (*platform.View, *platform.Error) {
i, ok := s.viewKV.Load(id.String())
if !ok {
return nil, fmt.Errorf("view not found")
return nil, &platform.Error{
Code: platform.ENotFound,
Msg: "view not found",
}
}
d, ok := i.(*platform.View)
if !ok {
return nil, fmt.Errorf("type %T is not a view", i)
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: fmt.Sprintf("type %T is not a view", i),
}
}
return d, nil
}
// FindViewByID returns a single view by ID.
func (s *Service) FindViewByID(ctx context.Context, id platform.ID) (*platform.View, error) {
return s.loadView(ctx, id)
v, pe := s.loadView(ctx, id)
if pe != nil {
return nil, &platform.Error{
Err: pe,
Op: OpPrefix + platform.OpFindViewByID,
}
}
return v, nil
}
func filterViewFn(filter platform.ViewFilter) func(d *platform.View) bool {
@ -37,16 +50,22 @@ func filterViewFn(filter platform.ViewFilter) func(d *platform.View) bool {
// FindViews implements platform.ViewService interface.
func (s *Service) FindViews(ctx context.Context, filter platform.ViewFilter) ([]*platform.View, int, error) {
var ds []*platform.View
if filter.ID != nil {
d, err := s.FindViewByID(ctx, *filter.ID)
if err != nil {
return nil, 0, err
if err != nil && platform.ErrorCode(err) != platform.ENotFound {
return nil, 0, &platform.Error{
Err: err,
Op: OpPrefix + platform.OpFindViews,
}
}
if d != nil {
ds = append(ds, d)
}
return []*platform.View{d}, 1, nil
return ds, len(ds), nil
}
var ds []*platform.View
var err error
filterF := filterViewFn(filter)
s.viewKV.Range(func(k, v interface{}) bool {
@ -66,7 +85,13 @@ func (s *Service) FindViews(ctx context.Context, filter platform.ViewFilter) ([]
// CreateView implements platform.ViewService interface.
func (s *Service) CreateView(ctx context.Context, c *platform.View) error {
c.ID = s.IDGenerator.ID()
return s.PutView(ctx, c)
if err := s.PutView(ctx, c); err != nil {
return &platform.Error{
Err: err,
Op: OpPrefix + platform.OpCreateView,
}
}
return nil
}
// PutView implements platform.ViewService interface.
@ -82,7 +107,10 @@ func (s *Service) PutView(ctx context.Context, c *platform.View) error {
func (s *Service) UpdateView(ctx context.Context, id platform.ID, upd platform.ViewUpdate) (*platform.View, error) {
c, err := s.FindViewByID(ctx, id)
if err != nil {
return nil, err
return nil, &platform.Error{
Err: err,
Op: OpPrefix + platform.OpUpdateView,
}
}
if upd.Name != nil {
@ -101,7 +129,10 @@ func (s *Service) UpdateView(ctx context.Context, id platform.ID, upd platform.V
// DeleteView implements platform.ViewService interface.
func (s *Service) DeleteView(ctx context.Context, id platform.ID) error {
if _, err := s.FindViewByID(ctx, id); err != nil {
return err
return &platform.Error{
Err: err,
Op: OpPrefix + platform.OpDeleteView,
}
}
s.viewKV.Delete(id.String())
return nil

View File

@ -8,7 +8,7 @@ import (
platformtesting "github.com/influxdata/platform/testing"
)
func initViewService(f platformtesting.ViewFields, t *testing.T) (platform.ViewService, func()) {
func initViewService(f platformtesting.ViewFields, t *testing.T) (platform.ViewService, string, func()) {
s := NewService()
s.IDGenerator = f.IDGenerator
ctx := context.TODO()
@ -17,7 +17,7 @@ func initViewService(f platformtesting.ViewFields, t *testing.T) (platform.ViewS
t.Fatalf("failed to populate Views")
}
}
return s, func() {}
return s, OpPrefix, func() {}
}
func TestViewService_CreateView(t *testing.T) {

View File

@ -3,7 +3,6 @@ package testing
import (
"bytes"
"context"
"fmt"
"sort"
"testing"
@ -39,7 +38,7 @@ type ViewFields struct {
// CreateView testing
func CreateView(
init func(ViewFields, *testing.T) (platform.ViewService, func()),
init func(ViewFields, *testing.T) (platform.ViewService, string, func()),
t *testing.T,
) {
type args struct {
@ -110,19 +109,11 @@ func CreateView(
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.CreateView(ctx, tt.args.view)
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)
defer s.DeleteView(ctx, tt.args.view.ID)
views, _, err := s.FindViews(ctx, platform.ViewFilter{})
@ -138,7 +129,7 @@ func CreateView(
// FindViewByID testing
func FindViewByID(
init func(ViewFields, *testing.T) (platform.ViewService, func()),
init func(ViewFields, *testing.T) (platform.ViewService, string, func()),
t *testing.T,
) {
type args struct {
@ -194,24 +185,50 @@ func FindViewByID(
},
},
},
{
name: "find view by id not found",
fields: ViewFields{
Views: []*platform.View{
{
ViewContents: platform.ViewContents{
ID: MustIDBase16(viewOneID),
Name: "view1",
},
Properties: platform.EmptyViewProperties{},
},
{
ViewContents: platform.ViewContents{
ID: MustIDBase16(viewTwoID),
Name: "view2",
},
Properties: platform.TableViewProperties{
Type: "table",
TimeFormat: "rfc3339",
},
},
},
},
args: args{
id: MustIDBase16(threeID),
},
wants: wants{
err: &platform.Error{
Code: platform.ENotFound,
Op: platform.OpFindViewByID,
Msg: "view 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()
view, err := s.FindViewByID(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(view, tt.wants.view, viewCmpOptions...); diff != "" {
t.Errorf("view is different -got/+want\ndiff %s", diff)
@ -222,7 +239,7 @@ func FindViewByID(
// FindViews testing
func FindViews(
init func(ViewFields, *testing.T) (platform.ViewService, func()),
init func(ViewFields, *testing.T) (platform.ViewService, string, func()),
t *testing.T,
) {
type args struct {
@ -326,11 +343,41 @@ func FindViews(
},
},
},
{
name: "find view by id not found",
fields: ViewFields{
Views: []*platform.View{
{
ViewContents: platform.ViewContents{
ID: MustIDBase16(viewOneID),
Name: "view1",
},
Properties: platform.EmptyViewProperties{},
},
{
ViewContents: platform.ViewContents{
ID: MustIDBase16(viewTwoID),
Name: "view2",
},
Properties: platform.TableViewProperties{
Type: "table",
TimeFormat: "rfc3339",
},
},
},
},
args: args{
ID: MustIDBase16(threeID),
},
wants: wants{
views: []*platform.View{},
},
},
}
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()
@ -340,15 +387,7 @@ func FindViews(
}
views, _, err := s.FindViews(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(views, tt.wants.views, viewCmpOptions...); diff != "" {
t.Errorf("views are different -got/+want\ndiff %s", diff)
@ -359,7 +398,7 @@ func FindViews(
// DeleteView testing
func DeleteView(
init func(ViewFields, *testing.T) (platform.ViewService, func()),
init func(ViewFields, *testing.T) (platform.ViewService, string, func()),
t *testing.T,
) {
type args struct {
@ -444,7 +483,11 @@ func DeleteView(
ID: MustIDBase16(viewThreeID),
},
wants: wants{
err: fmt.Errorf("view not found"),
err: &platform.Error{
Code: platform.ENotFound,
Op: platform.OpDeleteView,
Msg: "view not found",
},
views: []*platform.View{
{
ViewContents: platform.ViewContents{
@ -470,19 +513,11 @@ func DeleteView(
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.DeleteView(ctx, 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.ViewFilter{}
views, _, err := s.FindViews(ctx, filter)
@ -498,7 +533,7 @@ func DeleteView(
// UpdateView testing
func UpdateView(
init func(ViewFields, *testing.T) (platform.ViewService, func()),
init func(ViewFields, *testing.T) (platform.ViewService, string, func()),
t *testing.T,
) {
type args struct {
@ -597,11 +632,46 @@ func UpdateView(
},
},
},
{
name: "update id not exists",
fields: ViewFields{
Views: []*platform.View{
{
ViewContents: platform.ViewContents{
ID: MustIDBase16(viewOneID),
Name: "view1",
},
Properties: platform.EmptyViewProperties{},
},
{
ViewContents: platform.ViewContents{
ID: MustIDBase16(viewTwoID),
Name: "view2",
},
Properties: platform.TableViewProperties{
Type: "table",
TimeFormat: "rfc3339",
},
},
},
},
args: args{
id: MustIDBase16(threeID),
name: "changed",
},
wants: wants{
err: &platform.Error{
Code: platform.ENotFound,
Op: platform.OpUpdateView,
Msg: "view 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()
@ -614,15 +684,7 @@ func UpdateView(
}
view, err := s.UpdateView(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(view, tt.wants.view, viewCmpOptions...); diff != "" {
t.Errorf("view is different -got/+want\ndiff %s", diff)

20
view.go
View File

@ -6,8 +6,17 @@ import (
"fmt"
)
// ErrViewNotFound is the error for a missing View.
const ErrViewNotFound = ChronografError("view not found")
// ErrViewNotFound is the error msg for a missing View.
const ErrViewNotFound = "view not found"
// ops for view.
const (
OpFindViewByID = "FindViewByID"
OpFindViews = "FindViews"
OpCreateView = "CreateView"
OpUpdateView = "UpdateView"
OpDeleteView = "DeleteView"
)
// ViewService represents a service for managing View data.
type ViewService interface {
@ -36,10 +45,13 @@ type ViewUpdate struct {
}
// Valid validates the update struct. It expects minimal values to be set.
func (u ViewUpdate) Valid() error {
func (u ViewUpdate) Valid() *Error {
_, ok := u.Properties.(EmptyViewProperties)
if u.Name == nil && ok {
return fmt.Errorf("expected at least one attribute to be updated")
return &Error{
Code: EInvalid,
Msg: "expected at least one attribute to be updated",
}
}
return nil