Merge pull request #1100 from influxdata/feat/dashboard-times

Add CreatedAt and UpdatedAt fields to dashboards
pull/10616/head
Michael Desa 2018-10-23 13:50:49 -04:00 committed by GitHub
commit 0a7a061ae7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 345 additions and 65 deletions

View File

@ -32,6 +32,7 @@ type Client struct {
IDGenerator platform.IDGenerator
TokenGenerator platform.TokenGenerator
time func() time.Time
}
// NewClient returns an instance of a Client.
@ -40,6 +41,7 @@ func NewClient() *Client {
Logger: zap.NewNop(),
IDGenerator: snowflake.NewIDGenerator(),
TokenGenerator: rand.NewTokenGenerator(64),
time: time.Now,
}
}
@ -54,6 +56,12 @@ func (c *Client) WithLogger(l *zap.Logger) {
c.Logger = l
}
// WithTime sets the function for computing the current time. Used for updating meta data
// about objects stored. Should only be used in tests for mocking.
func (c *Client) WithTime(fn func() time.Time) {
c.time = fn
}
// Open / create boltDB file.
func (c *Client) Open(ctx context.Context) error {
if _, err := os.Stat(c.Path); err != nil && !os.IsNotExist(err) {

View File

@ -107,7 +107,7 @@ func filterDashboardsFn(filter platform.DashboardFilter) func(d *platform.Dashbo
}
// FindDashboards retrives all dashboards that match an arbitrary dashboard filter.
func (c *Client) FindDashboards(ctx context.Context, filter platform.DashboardFilter) ([]*platform.Dashboard, int, error) {
func (c *Client) FindDashboards(ctx context.Context, filter platform.DashboardFilter, opts platform.FindOptions) ([]*platform.Dashboard, int, error) {
if len(filter.IDs) == 1 {
d, err := c.FindDashboardByID(ctx, *filter.IDs[0])
if err != nil {
@ -131,6 +131,8 @@ func (c *Client) FindDashboards(ctx context.Context, filter platform.DashboardFi
return nil, 0, err
}
platform.SortDashboards(opts.SortBy, ds)
return ds, len(ds), nil
}
@ -165,7 +167,9 @@ func (c *Client) CreateDashboard(ctx context.Context, d *platform.Dashboard) err
}
}
return c.putDashboard(ctx, tx, d)
d.Meta.CreatedAt = c.time()
return c.putDashboardWithMeta(ctx, tx, d)
})
}
@ -231,7 +235,7 @@ func (c *Client) ReplaceDashboardCells(ctx context.Context, id platform.ID, cs [
d.Cells = cs
return c.putDashboard(ctx, tx, d)
return c.putDashboardWithMeta(ctx, tx, d)
})
}
@ -248,7 +252,8 @@ func (c *Client) AddDashboardCell(ctx context.Context, id platform.ID, cell *pla
}
d.Cells = append(d.Cells, cell)
return c.putDashboard(ctx, tx, d)
return c.putDashboardWithMeta(ctx, tx, d)
})
}
@ -276,7 +281,8 @@ func (c *Client) RemoveDashboardCell(ctx context.Context, dashboardID, cellID pl
}
d.Cells = append(d.Cells[:idx], d.Cells[idx+1:]...)
return c.putDashboard(ctx, tx, d)
return c.putDashboardWithMeta(ctx, tx, d)
})
}
@ -306,7 +312,7 @@ func (c *Client) UpdateDashboardCell(ctx context.Context, dashboardID, cellID pl
cell = d.Cells[idx]
return c.putDashboard(ctx, tx, d)
return c.putDashboardWithMeta(ctx, tx, d)
})
if err != nil {
@ -338,6 +344,11 @@ func (c *Client) putDashboard(ctx context.Context, tx *bolt.Tx, d *platform.Dash
return nil
}
func (c *Client) putDashboardWithMeta(ctx context.Context, tx *bolt.Tx, d *platform.Dashboard) error {
d.Meta.UpdatedAt = c.time()
return c.putDashboard(ctx, tx, d)
}
// forEachDashboard will iterate through all dashboards while fn returns true.
func (c *Client) forEachDashboard(ctx context.Context, tx *bolt.Tx, fn func(*platform.Dashboard) bool) error {
cur := tx.Bucket(dashboardBucket).Cursor()
@ -383,7 +394,7 @@ func (c *Client) updateDashboard(ctx context.Context, tx *bolt.Tx, id platform.I
return nil, err
}
if err := c.putDashboard(ctx, tx, d); err != nil {
if err := c.putDashboardWithMeta(ctx, tx, d); err != nil {
return nil, err
}

View File

@ -14,6 +14,7 @@ func initDashboardService(f platformtesting.DashboardFields, t *testing.T) (plat
t.Fatalf("failed to create new bolt client: %v", err)
}
c.IDGenerator = f.IDGenerator
c.WithTime(f.NowFn)
ctx := context.TODO()
for _, b := range f.Dashboards {
if err := c.PutDashboard(ctx, b); err != nil {

View File

@ -3,6 +3,8 @@ package platform
import (
"context"
"fmt"
"sort"
"time"
)
// ErrDashboardNotFound is the error for a missing dashboard.
@ -18,7 +20,7 @@ type DashboardService interface {
// FindDashboards returns a list of dashboards that match filter and the total count of matching dashboards.
// Additional options provide pagination & sorting.
FindDashboards(ctx context.Context, filter DashboardFilter) ([]*Dashboard, int, error)
FindDashboards(ctx context.Context, filter DashboardFilter, opts FindOptions) ([]*Dashboard, int, error)
// CreateDashboard creates a new dashboard and sets b.ID with the new identifier.
CreateDashboard(ctx context.Context, b *Dashboard) error
@ -45,10 +47,47 @@ type DashboardService interface {
// Dashboard represents all visual and query data for a dashboard
type Dashboard struct {
ID ID `json:"id,omitempty"`
Name string `json:"name"`
Description string `json:"description"`
Cells []*Cell `json:"cells"`
ID ID `json:"id,omitempty"`
Name string `json:"name"`
Description string `json:"description"`
Cells []*Cell `json:"cells"`
Meta DashboardMeta `json:"meta"`
}
// Dashboard meta contains meta information about dashboards
type DashboardMeta struct {
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
}
// DefaultDashboardFindOptions are the default find options for dashboards
var DefaultDashboardFindOptions = FindOptions{
SortBy: "ID",
}
// SortDashboards sorts a slice of dashboards by a field.
func SortDashboards(by string, ds []*Dashboard) {
var sorter func(i, j int) bool
switch by {
case "CreatedAt":
sorter = func(i, j int) bool {
return ds[j].Meta.CreatedAt.After(ds[i].Meta.CreatedAt)
}
case "UpdatedAt":
sorter = func(i, j int) bool {
return ds[j].Meta.UpdatedAt.After(ds[i].Meta.UpdatedAt)
}
case "Name":
sorter = func(i, j int) bool {
return ds[i].Name < ds[j].Name
}
default:
sorter = func(i, j int) bool {
return ds[i].ID < ds[j].ID
}
}
sort.Slice(ds, sorter)
}
// Cell holds positional information about a cell on dashboard and a reference to a cell.

View File

@ -73,13 +73,6 @@ type dashboardResponse struct {
}
func (d dashboardResponse) toPlatform() *platform.Dashboard {
if len(d.Cells) == 0 {
return &platform.Dashboard{
ID: d.ID,
Name: d.Name,
}
}
cells := make([]*platform.Cell, 0, len(d.Cells))
for i := range d.Cells {
cells = append(cells, d.Cells[i].toPlatform())
@ -87,6 +80,7 @@ func (d dashboardResponse) toPlatform() *platform.Dashboard {
return &platform.Dashboard{
ID: d.ID,
Name: d.Name,
Meta: d.Meta,
Cells: cells,
}
}
@ -174,7 +168,7 @@ func (h *DashboardHandler) handleGetDashboards(w http.ResponseWriter, r *http.Re
}
}
dashboards, _, err := h.DashboardService.FindDashboards(ctx, req.filter)
dashboards, _, err := h.DashboardService.FindDashboards(ctx, req.filter, req.opts)
if err != nil {
EncodeError(ctx, errors.InternalErrorf("Error loading dashboards: %v", err), w)
return
@ -188,6 +182,7 @@ func (h *DashboardHandler) handleGetDashboards(w http.ResponseWriter, r *http.Re
type getDashboardsRequest struct {
filter platform.DashboardFilter
opts platform.FindOptions
ownerID *platform.ID
}
@ -211,6 +206,12 @@ func decodeGetDashboardsRequest(ctx context.Context, r *http.Request) (*getDashb
}
}
req.opts = platform.DefaultDashboardFindOptions
if sortBy := qp.Get("sortBy"); sortBy != "" {
req.opts.SortBy = sortBy
}
return req, nil
}
@ -685,13 +686,14 @@ func (s *DashboardService) FindDashboardByID(ctx context.Context, id platform.ID
// FindDashboards returns a list of dashboards that match filter and the total count of matching dashboards.
// Additional options provide pagination & sorting.
func (s *DashboardService) FindDashboards(ctx context.Context, filter platform.DashboardFilter) ([]*platform.Dashboard, int, error) {
func (s *DashboardService) FindDashboards(ctx context.Context, filter platform.DashboardFilter, opts platform.FindOptions) ([]*platform.Dashboard, int, error) {
url, err := newURL(s.Addr, dashboardsPath)
if err != nil {
return nil, 0, err
}
qp := url.Query()
qp.Add("sortBy", opts.SortBy)
for _, id := range filter.IDs {
qp.Add("id", id.String())
}
@ -754,7 +756,11 @@ func (s *DashboardService) CreateDashboard(ctx context.Context, d *platform.Dash
return err
}
return json.NewDecoder(resp.Body).Decode(d)
if err := json.NewDecoder(resp.Body).Decode(d); err != nil {
return err
}
return nil
}
// UpdateDashboard updates a single dashboard with changeset.

View File

@ -9,6 +9,7 @@ import (
"net/http"
"net/http/httptest"
"testing"
"time"
"github.com/influxdata/platform"
"github.com/influxdata/platform/inmem"
@ -40,12 +41,16 @@ func TestService_handleGetDashboards(t *testing.T) {
name: "get all dashboards",
fields: fields{
&mock.DashboardService{
FindDashboardsF: func(ctx context.Context, filter platform.DashboardFilter) ([]*platform.Dashboard, int, error) {
FindDashboardsF: func(ctx context.Context, filter platform.DashboardFilter, opts platform.FindOptions) ([]*platform.Dashboard, int, error) {
return []*platform.Dashboard{
{
ID: platformtesting.MustIDBase16("da7aba5e5d81e550"),
Name: "hello",
Description: "oh hello there!",
Meta: platform.DashboardMeta{
CreatedAt: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC),
UpdatedAt: time.Date(2009, time.November, 10, 24, 0, 0, 0, time.UTC),
},
Cells: []*platform.Cell{
{
ID: platformtesting.MustIDBase16("da7aba5e5d81e550"),
@ -58,7 +63,11 @@ func TestService_handleGetDashboards(t *testing.T) {
},
},
{
ID: platformtesting.MustIDBase16("0ca2204eca2204e0"),
ID: platformtesting.MustIDBase16("0ca2204eca2204e0"),
Meta: platform.DashboardMeta{
CreatedAt: time.Date(2012, time.November, 10, 23, 0, 0, 0, time.UTC),
UpdatedAt: time.Date(2012, time.November, 10, 24, 0, 0, 0, time.UTC),
},
Name: "example",
},
}, 2, nil
@ -79,6 +88,10 @@ func TestService_handleGetDashboards(t *testing.T) {
"id": "da7aba5e5d81e550",
"name": "hello",
"description": "oh hello there!",
"meta": {
"createdAt": "2009-11-10T23:00:00Z",
"updatedAt": "2009-11-11T00:00:00Z"
},
"cells": [
{
"id": "da7aba5e5d81e550",
@ -102,6 +115,10 @@ func TestService_handleGetDashboards(t *testing.T) {
"id": "0ca2204eca2204e0",
"name": "example",
"description": "",
"meta": {
"createdAt": "2012-11-10T23:00:00Z",
"updatedAt": "2012-11-11T00:00:00Z"
},
"cells": [],
"links": {
"self": "/api/v2/dashboards/0ca2204eca2204e0",
@ -117,7 +134,7 @@ func TestService_handleGetDashboards(t *testing.T) {
name: "get all dashboards when there are none",
fields: fields{
&mock.DashboardService{
FindDashboardsF: func(ctx context.Context, filter platform.DashboardFilter) ([]*platform.Dashboard, int, error) {
FindDashboardsF: func(ctx context.Context, filter platform.DashboardFilter, opts platform.FindOptions) ([]*platform.Dashboard, int, error) {
return []*platform.Dashboard{}, 0, nil
},
},
@ -201,7 +218,11 @@ func TestService_handleGetDashboard(t *testing.T) {
FindDashboardByIDF: func(ctx context.Context, id platform.ID) (*platform.Dashboard, error) {
if id == platformtesting.MustIDBase16("020f755c3c082000") {
return &platform.Dashboard{
ID: platformtesting.MustIDBase16("020f755c3c082000"),
ID: platformtesting.MustIDBase16("020f755c3c082000"),
Meta: platform.DashboardMeta{
CreatedAt: time.Date(2012, time.November, 10, 23, 0, 0, 0, time.UTC),
UpdatedAt: time.Date(2012, time.November, 10, 24, 0, 0, 0, time.UTC),
},
Name: "hello",
Cells: []*platform.Cell{
{
@ -231,6 +252,10 @@ func TestService_handleGetDashboard(t *testing.T) {
"id": "020f755c3c082000",
"name": "hello",
"description": "",
"meta": {
"createdAt": "2012-11-10T23:00:00Z",
"updatedAt": "2012-11-11T00:00:00Z"
},
"cells": [
{
"id": "da7aba5e5d81e550",
@ -335,6 +360,10 @@ func TestService_handlePostDashboard(t *testing.T) {
&mock.DashboardService{
CreateDashboardF: func(ctx context.Context, c *platform.Dashboard) error {
c.ID = platformtesting.MustIDBase16("020f755c3c082000")
c.Meta = platform.DashboardMeta{
CreatedAt: time.Date(2012, time.November, 10, 23, 0, 0, 0, time.UTC),
UpdatedAt: time.Date(2012, time.November, 10, 24, 0, 0, 0, time.UTC),
}
return nil
},
},
@ -364,6 +393,10 @@ func TestService_handlePostDashboard(t *testing.T) {
"id": "020f755c3c082000",
"name": "hello",
"description": "howdy there",
"meta": {
"createdAt": "2012-11-10T23:00:00Z",
"updatedAt": "2012-11-11T00:00:00Z"
},
"cells": [
{
"id": "da7aba5e5d81e550",
@ -547,6 +580,10 @@ func TestService_handlePatchDashboard(t *testing.T) {
d := &platform.Dashboard{
ID: platformtesting.MustIDBase16("020f755c3c082000"),
Name: "hello",
Meta: platform.DashboardMeta{
CreatedAt: time.Date(2012, time.November, 10, 23, 0, 0, 0, time.UTC),
UpdatedAt: time.Date(2012, time.November, 10, 25, 0, 0, 0, time.UTC),
},
Cells: []*platform.Cell{
{
ID: platformtesting.MustIDBase16("da7aba5e5d81e550"),
@ -582,6 +619,10 @@ func TestService_handlePatchDashboard(t *testing.T) {
"id": "020f755c3c082000",
"name": "example",
"description": "",
"meta": {
"createdAt": "2012-11-10T23:00:00Z",
"updatedAt": "2012-11-11T01:00:00Z"
},
"cells": [
{
"id": "da7aba5e5d81e550",
@ -1032,11 +1073,11 @@ func initDashboardService(f platformtesting.DashboardFields, t *testing.T) (plat
t.Helper()
svc := inmem.NewService()
svc.IDGenerator = f.IDGenerator
svc.WithTime(f.NowFn)
ctx := context.Background()
for _, o := range f.Dashboards {
if err := svc.PutDashboard(ctx, o); err != nil {
t.Fatalf("failed to populate organizations")
for _, d := range f.Dashboards {
if err := svc.PutDashboard(ctx, d); err != nil {
t.Fatalf("failed to populate dashboard")
}
}
for _, b := range f.Views {

View File

@ -1014,6 +1014,15 @@ paths:
description: specifies the owner id to return resources for
schema:
type: string
- in: query
name: sortBy
description: specifies the owner id to return resources for
schema:
type: string
enum:
- "ID"
- "CreatedAt"
- "UpdatedAt"
- in: query
name: id
description: ID list of dashboards to return. If both this and owner are specified, only ids is used.
@ -4397,6 +4406,15 @@ components:
description:
type: string
description: user-facing description of the dashboard
meta:
type: object
properties:
createdAt:
type: string
format: date
updatedAt:
type: string
format: date
cells:
$ref: "#/components/schemas/Cells"
Dashboards:
@ -4493,7 +4511,7 @@ components:
type:
type: string
enum: [input, output, processor, aggregator]
comment:
comment:
type: string
config:
oneOf:
@ -4649,7 +4667,7 @@ components:
bucket:
type: string
retentionPeriodHrs:
type: integer
type: integer
required:
- username
- password

View File

@ -42,7 +42,7 @@ func filterDashboardFn(filter platform.DashboardFilter) func(d *platform.Dashboa
}
// FindDashboards implements platform.DashboardService interface.
func (s *Service) FindDashboards(ctx context.Context, filter platform.DashboardFilter) ([]*platform.Dashboard, int, error) {
func (s *Service) FindDashboards(ctx context.Context, filter platform.DashboardFilter, opts platform.FindOptions) ([]*platform.Dashboard, int, error) {
if len(filter.IDs) == 1 {
d, err := s.FindDashboardByID(ctx, *filter.IDs[0])
if err != nil {
@ -66,13 +66,17 @@ func (s *Service) FindDashboards(ctx context.Context, filter platform.DashboardF
}
return true
})
platform.SortDashboards(opts.SortBy, ds)
return ds, len(ds), err
}
// CreateDashboard implements platform.DashboardService interface.
func (s *Service) CreateDashboard(ctx context.Context, d *platform.Dashboard) error {
d.ID = s.IDGenerator.ID()
return s.PutDashboard(ctx, d)
d.Meta.CreatedAt = s.time()
return s.PutDashboardWithMeta(ctx, d)
}
// PutDashboard implements platform.DashboardService interface.
@ -81,6 +85,12 @@ func (s *Service) PutDashboard(ctx context.Context, o *platform.Dashboard) error
return nil
}
// PutDashboardWithMeta sets a dashboard while updating the meta field of a dashboard.
func (s *Service) PutDashboardWithMeta(ctx context.Context, d *platform.Dashboard) error {
d.Meta.UpdatedAt = s.time()
return s.PutDashboard(ctx, d)
}
// UpdateDashboard implements platform.DashboardService interface.
func (s *Service) UpdateDashboard(ctx context.Context, id platform.ID, upd platform.DashboardUpdate) (*platform.Dashboard, error) {
if err := upd.Valid(); err != nil {
@ -96,7 +106,10 @@ func (s *Service) UpdateDashboard(ctx context.Context, id platform.ID, upd platf
return nil, err
}
s.dashboardKV.Store(d.ID.String(), d)
if err := s.PutDashboardWithMeta(ctx, d); err != nil {
return nil, err
}
return d, nil
}
@ -121,7 +134,7 @@ func (s *Service) AddDashboardCell(ctx context.Context, id platform.ID, cell *pl
}
d.Cells = append(d.Cells, cell)
return s.PutDashboard(ctx, d)
return s.PutDashboardWithMeta(ctx, d)
}
// PutDashboardCell replaces a dashboad cell with the cell contents.
@ -163,7 +176,7 @@ func (s *Service) RemoveDashboardCell(ctx context.Context, dashboardID platform.
}
d.Cells = append(d.Cells[:idx], d.Cells[idx+1:]...)
return s.PutDashboard(ctx, d)
return s.PutDashboardWithMeta(ctx, d)
}
@ -191,7 +204,7 @@ func (s *Service) UpdateDashboardCell(ctx context.Context, dashboardID platform.
cell := d.Cells[idx]
if err := s.PutDashboard(ctx, d); err != nil {
if err := s.PutDashboardWithMeta(ctx, d); err != nil {
return nil, err
}
@ -227,5 +240,5 @@ func (s *Service) ReplaceDashboardCells(ctx context.Context, id platform.ID, cs
d.Cells = cs
return s.PutDashboard(ctx, d)
return s.PutDashboardWithMeta(ctx, d)
}

View File

@ -12,6 +12,7 @@ func initDashboardService(f platformtesting.DashboardFields, t *testing.T) (plat
s := NewService()
s.IDGenerator = f.IDGenerator
ctx := context.Background()
s.WithTime(f.NowFn)
for _, b := range f.Dashboards {
if err := s.PutDashboard(ctx, b); err != nil {
t.Fatalf("failed to populate Dashboards")

View File

@ -2,6 +2,7 @@ package inmem
import (
"sync"
"time"
"github.com/influxdata/platform"
"github.com/influxdata/platform/rand"
@ -24,6 +25,7 @@ type Service struct {
TokenGenerator platform.TokenGenerator
IDGenerator platform.IDGenerator
time func() time.Time
}
// NewService creates an instance of a Service.
@ -31,5 +33,12 @@ func NewService() *Service {
return &Service{
TokenGenerator: rand.NewTokenGenerator(64),
IDGenerator: snowflake.NewIDGenerator(),
time: time.Now,
}
}
// WithTime sets the function for computing the current time. Used for updating meta data
// about objects stored. Should only be used in tests for mocking.
func (s *Service) WithTime(fn func() time.Time) {
s.time = fn
}

View File

@ -11,7 +11,7 @@ var _ platform.DashboardService = &DashboardService{}
type DashboardService struct {
CreateDashboardF func(context.Context, *platform.Dashboard) error
FindDashboardByIDF func(context.Context, platform.ID) (*platform.Dashboard, error)
FindDashboardsF func(context.Context, platform.DashboardFilter) ([]*platform.Dashboard, int, error)
FindDashboardsF func(context.Context, platform.DashboardFilter, platform.FindOptions) ([]*platform.Dashboard, int, error)
UpdateDashboardF func(context.Context, platform.ID, platform.DashboardUpdate) (*platform.Dashboard, error)
DeleteDashboardF func(context.Context, platform.ID) error
@ -26,8 +26,8 @@ func (s *DashboardService) FindDashboardByID(ctx context.Context, id platform.ID
return s.FindDashboardByIDF(ctx, id)
}
func (s *DashboardService) FindDashboards(ctx context.Context, filter platform.DashboardFilter) ([]*platform.Dashboard, int, error) {
return s.FindDashboardsF(ctx, filter)
func (s *DashboardService) FindDashboards(ctx context.Context, filter platform.DashboardFilter, opts platform.FindOptions) ([]*platform.Dashboard, int, error) {
return s.FindDashboardsF(ctx, filter, opts)
}
func (s *DashboardService) CreateDashboard(ctx context.Context, b *platform.Dashboard) error {

View File

@ -4,10 +4,11 @@ import (
"bytes"
"context"
"fmt"
"sort"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/influxdata/platform"
"github.com/influxdata/platform/mock"
)
@ -26,18 +27,13 @@ var dashboardCmpOptions = cmp.Options{
cmp.Comparer(func(x, y []byte) bool {
return bytes.Equal(x, y)
}),
cmp.Transformer("Sort", func(in []*platform.Dashboard) []*platform.Dashboard {
out := append([]*platform.Dashboard(nil), in...) // Copy input to avoid mutating it
sort.Slice(out, func(i, j int) bool {
return out[i].ID.String() > out[j].ID.String()
})
return out
}),
cmpopts.EquateEmpty(),
}
// DashboardFields will include the IDGenerator, and dashboards
type DashboardFields struct {
IDGenerator platform.IDGenerator
NowFn func() time.Time
Dashboards []*platform.Dashboard
Views []*platform.View
}
@ -118,6 +114,7 @@ func CreateDashboard(
return MustIDBase16(dashTwoID)
},
},
NowFn: func() time.Time { return time.Date(2009, time.November, 10, 24, 0, 0, 0, time.UTC) },
Dashboards: []*platform.Dashboard{
{
ID: MustIDBase16(dashOneID),
@ -140,6 +137,10 @@ func CreateDashboard(
{
ID: MustIDBase16(dashTwoID),
Name: "dashboard2",
Meta: platform.DashboardMeta{
CreatedAt: time.Date(2009, time.November, 10, 24, 0, 0, 0, time.UTC),
UpdatedAt: time.Date(2009, time.November, 10, 24, 0, 0, 0, time.UTC),
},
},
},
},
@ -152,6 +153,7 @@ func CreateDashboard(
return MustIDBase16(dashTwoID)
},
},
NowFn: func() time.Time { return time.Date(2009, time.November, 10, 24, 0, 0, 0, time.UTC) },
Dashboards: []*platform.Dashboard{
{
ID: MustIDBase16(dashOneID),
@ -173,6 +175,10 @@ func CreateDashboard(
{
ID: MustIDBase16(dashTwoID),
Name: "dashboard2",
Meta: platform.DashboardMeta{
CreatedAt: time.Date(2009, time.November, 10, 24, 0, 0, 0, time.UTC),
UpdatedAt: time.Date(2009, time.November, 10, 24, 0, 0, 0, time.UTC),
},
},
},
},
@ -196,7 +202,7 @@ func CreateDashboard(
}
defer s.DeleteDashboard(ctx, tt.args.dashboard.ID)
dashboards, _, err := s.FindDashboards(ctx, platform.DashboardFilter{})
dashboards, _, err := s.FindDashboards(ctx, platform.DashboardFilter{}, platform.DefaultDashboardFindOptions)
if err != nil {
t.Fatalf("failed to retrieve dashboards: %v", err)
}
@ -235,6 +241,7 @@ func AddDashboardCell(
return MustIDBase16(dashTwoID)
},
},
NowFn: func() time.Time { return time.Date(2009, time.November, 10, 24, 0, 0, 0, time.UTC) },
Dashboards: []*platform.Dashboard{
{
ID: MustIDBase16(dashOneID),
@ -259,7 +266,10 @@ func AddDashboardCell(
wants: wants{
dashboards: []*platform.Dashboard{
{
ID: MustIDBase16(dashOneID),
ID: MustIDBase16(dashOneID),
Meta: platform.DashboardMeta{
UpdatedAt: time.Date(2009, time.November, 10, 24, 0, 0, 0, time.UTC),
},
Name: "dashboard1",
Cells: []*platform.Cell{
{
@ -274,6 +284,7 @@ func AddDashboardCell(
{
name: "add cell with no id",
fields: DashboardFields{
NowFn: func() time.Time { return time.Date(2009, time.November, 10, 24, 0, 0, 0, time.UTC) },
IDGenerator: &mock.IDGenerator{
IDFn: func() platform.ID {
return MustIDBase16(dashTwoID)
@ -302,7 +313,10 @@ func AddDashboardCell(
wants: wants{
dashboards: []*platform.Dashboard{
{
ID: MustIDBase16(dashOneID),
ID: MustIDBase16(dashOneID),
Meta: platform.DashboardMeta{
UpdatedAt: time.Date(2009, time.November, 10, 24, 0, 0, 0, time.UTC),
},
Name: "dashboard1",
Cells: []*platform.Cell{
{
@ -333,7 +347,7 @@ func AddDashboardCell(
}
defer s.DeleteDashboard(ctx, tt.args.dashboardID)
dashboards, _, err := s.FindDashboards(ctx, platform.DashboardFilter{})
dashboards, _, err := s.FindDashboards(ctx, platform.DashboardFilter{}, platform.DefaultDashboardFindOptions)
if err != nil {
t.Fatalf("failed to retrieve dashboards: %v", err)
}
@ -419,8 +433,9 @@ func FindDashboards(
t *testing.T,
) {
type args struct {
IDs []*platform.ID
name string
IDs []*platform.ID
name string
findOptions platform.FindOptions
}
type wants struct {
@ -447,7 +462,9 @@ func FindDashboards(
},
},
},
args: args{},
args: args{
findOptions: platform.DefaultDashboardFindOptions,
},
wants: wants{
dashboards: []*platform.Dashboard{
{
@ -461,6 +478,94 @@ func FindDashboards(
},
},
},
{
name: "find all dashboards sorted by created at",
fields: DashboardFields{
Dashboards: []*platform.Dashboard{
{
ID: MustIDBase16(dashOneID),
Meta: platform.DashboardMeta{
CreatedAt: time.Date(2009, time.November, 10, 24, 0, 0, 0, time.UTC),
},
Name: "abc",
},
{
ID: MustIDBase16(dashTwoID),
Meta: platform.DashboardMeta{
CreatedAt: time.Date(2004, time.November, 10, 24, 0, 0, 0, time.UTC),
},
Name: "xyz",
},
},
},
args: args{
findOptions: platform.FindOptions{
SortBy: "CreatedAt",
},
},
wants: wants{
dashboards: []*platform.Dashboard{
{
ID: MustIDBase16(dashTwoID),
Name: "xyz",
Meta: platform.DashboardMeta{
CreatedAt: time.Date(2004, time.November, 10, 24, 0, 0, 0, time.UTC),
},
},
{
ID: MustIDBase16(dashOneID),
Name: "abc",
Meta: platform.DashboardMeta{
CreatedAt: time.Date(2009, time.November, 10, 24, 0, 0, 0, time.UTC),
},
},
},
},
},
{
name: "find all dashboards sorted by updated at",
fields: DashboardFields{
Dashboards: []*platform.Dashboard{
{
ID: MustIDBase16(dashOneID),
Meta: platform.DashboardMeta{
UpdatedAt: time.Date(2009, time.November, 10, 24, 0, 0, 0, time.UTC),
},
Name: "abc",
},
{
ID: MustIDBase16(dashTwoID),
Meta: platform.DashboardMeta{
UpdatedAt: time.Date(2010, time.November, 10, 24, 0, 0, 0, time.UTC),
},
Name: "xyz",
},
},
},
args: args{
findOptions: platform.FindOptions{
SortBy: "UpdatedAt",
},
},
wants: wants{
dashboards: []*platform.Dashboard{
{
ID: MustIDBase16(dashOneID),
Meta: platform.DashboardMeta{
UpdatedAt: time.Date(2009, time.November, 10, 24, 0, 0, 0, time.UTC),
},
Name: "abc",
},
{
ID: MustIDBase16(dashTwoID),
Meta: platform.DashboardMeta{
UpdatedAt: time.Date(2010, time.November, 10, 24, 0, 0, 0, time.UTC),
},
Name: "xyz",
},
},
},
},
{
name: "find dashboard by id",
fields: DashboardFields{
@ -479,6 +584,7 @@ func FindDashboards(
IDs: []*platform.ID{
idPtr(MustIDBase16(dashTwoID)),
},
findOptions: platform.DefaultDashboardFindOptions,
},
wants: wants{
dashboards: []*platform.Dashboard{
@ -508,6 +614,7 @@ func FindDashboards(
idPtr(MustIDBase16(dashOneID)),
idPtr(MustIDBase16(dashTwoID)),
},
findOptions: platform.DefaultDashboardFindOptions,
},
wants: wants{
dashboards: []*platform.Dashboard{
@ -535,7 +642,7 @@ func FindDashboards(
filter.IDs = tt.args.IDs
}
dashboards, _, err := s.FindDashboards(ctx, filter)
dashboards, _, err := s.FindDashboards(ctx, filter, tt.args.findOptions)
if (err != nil) != (tt.wants.err != nil) {
t.Fatalf("expected errors to be equal '%v' got '%v'", tt.wants.err, err)
}
@ -648,7 +755,7 @@ func DeleteDashboard(
}
filter := platform.DashboardFilter{}
dashboards, _, err := s.FindDashboards(ctx, filter)
dashboards, _, err := s.FindDashboards(ctx, filter, platform.DefaultDashboardFindOptions)
if err != nil {
t.Fatalf("failed to retrieve dashboards: %v", err)
}
@ -683,6 +790,7 @@ func UpdateDashboard(
{
name: "update name",
fields: DashboardFields{
NowFn: func() time.Time { return time.Date(2009, time.November, 10, 24, 0, 0, 0, time.UTC) },
Dashboards: []*platform.Dashboard{
{
ID: MustIDBase16(dashOneID),
@ -700,7 +808,10 @@ func UpdateDashboard(
},
wants: wants{
dashboard: &platform.Dashboard{
ID: MustIDBase16(dashOneID),
ID: MustIDBase16(dashOneID),
Meta: platform.DashboardMeta{
UpdatedAt: time.Date(2009, time.November, 10, 24, 0, 0, 0, time.UTC),
},
Name: "changed",
},
},
@ -708,6 +819,7 @@ func UpdateDashboard(
{
name: "update description",
fields: DashboardFields{
NowFn: func() time.Time { return time.Date(2009, time.November, 10, 24, 0, 0, 0, time.UTC) },
Dashboards: []*platform.Dashboard{
{
ID: MustIDBase16(dashOneID),
@ -728,12 +840,16 @@ func UpdateDashboard(
ID: MustIDBase16(dashOneID),
Name: "dashboard1",
Description: "changed",
Meta: platform.DashboardMeta{
UpdatedAt: time.Date(2009, time.November, 10, 24, 0, 0, 0, time.UTC),
},
},
},
},
{
name: "update description and name",
fields: DashboardFields{
NowFn: func() time.Time { return time.Date(2009, time.November, 10, 24, 0, 0, 0, time.UTC) },
Dashboards: []*platform.Dashboard{
{
ID: MustIDBase16(dashOneID),
@ -755,6 +871,9 @@ func UpdateDashboard(
ID: MustIDBase16(dashOneID),
Name: "changed",
Description: "changed",
Meta: platform.DashboardMeta{
UpdatedAt: time.Date(2009, time.November, 10, 24, 0, 0, 0, time.UTC),
},
},
},
},
@ -815,6 +934,7 @@ func RemoveDashboardCell(
{
name: "basic remove cell",
fields: DashboardFields{
NowFn: func() time.Time { return time.Date(2009, time.November, 10, 24, 0, 0, 0, time.UTC) },
IDGenerator: &mock.IDGenerator{
IDFn: func() platform.ID {
return MustIDBase16(dashTwoID)
@ -851,7 +971,10 @@ func RemoveDashboardCell(
wants: wants{
dashboards: []*platform.Dashboard{
{
ID: MustIDBase16(dashOneID),
ID: MustIDBase16(dashOneID),
Meta: platform.DashboardMeta{
UpdatedAt: time.Date(2009, time.November, 10, 24, 0, 0, 0, time.UTC),
},
Name: "dashboard1",
Cells: []*platform.Cell{
{
@ -882,7 +1005,7 @@ func RemoveDashboardCell(
}
defer s.DeleteDashboard(ctx, tt.args.dashboardID)
dashboards, _, err := s.FindDashboards(ctx, platform.DashboardFilter{})
dashboards, _, err := s.FindDashboards(ctx, platform.DashboardFilter{}, platform.DefaultDashboardFindOptions)
if err != nil {
t.Fatalf("failed to retrieve dashboards: %v", err)
}
@ -917,6 +1040,7 @@ func UpdateDashboardCell(
{
name: "basic remove cell",
fields: DashboardFields{
NowFn: func() time.Time { return time.Date(2009, time.November, 10, 24, 0, 0, 0, time.UTC) },
IDGenerator: &mock.IDGenerator{
IDFn: func() platform.ID {
return MustIDBase16(dashTwoID)
@ -950,7 +1074,10 @@ func UpdateDashboardCell(
wants: wants{
dashboards: []*platform.Dashboard{
{
ID: MustIDBase16(dashOneID),
ID: MustIDBase16(dashOneID),
Meta: platform.DashboardMeta{
UpdatedAt: time.Date(2009, time.November, 10, 24, 0, 0, 0, time.UTC),
},
Name: "dashboard1",
Cells: []*platform.Cell{
{
@ -986,7 +1113,7 @@ func UpdateDashboardCell(
}
defer s.DeleteDashboard(ctx, tt.args.dashboardID)
dashboards, _, err := s.FindDashboards(ctx, platform.DashboardFilter{})
dashboards, _, err := s.FindDashboards(ctx, platform.DashboardFilter{}, platform.DefaultDashboardFindOptions)
if err != nil {
t.Fatalf("failed to retrieve dashboards: %v", err)
}
@ -1020,6 +1147,7 @@ func ReplaceDashboardCells(
{
name: "basic replace cells",
fields: DashboardFields{
NowFn: func() time.Time { return time.Date(2009, time.November, 10, 24, 0, 0, 0, time.UTC) },
IDGenerator: &mock.IDGenerator{
IDFn: func() platform.ID {
return MustIDBase16(dashTwoID)
@ -1074,6 +1202,9 @@ func ReplaceDashboardCells(
{
ID: MustIDBase16(dashOneID),
Name: "dashboard1",
Meta: platform.DashboardMeta{
UpdatedAt: time.Date(2009, time.November, 10, 24, 0, 0, 0, time.UTC),
},
Cells: []*platform.Cell{
{
ID: MustIDBase16(dashTwoID),
@ -1093,6 +1224,7 @@ func ReplaceDashboardCells(
{
name: "try to add a cell that didn't previously exist",
fields: DashboardFields{
NowFn: func() time.Time { return time.Date(2009, time.November, 10, 24, 0, 0, 0, time.UTC) },
IDGenerator: &mock.IDGenerator{
IDFn: func() platform.ID {
return MustIDBase16(dashTwoID)
@ -1152,6 +1284,7 @@ func ReplaceDashboardCells(
{
name: "try to update a view during a replace",
fields: DashboardFields{
NowFn: func() time.Time { return time.Date(2009, time.November, 10, 24, 0, 0, 0, time.UTC) },
IDGenerator: &mock.IDGenerator{
IDFn: func() platform.ID {
return MustIDBase16(dashTwoID)
@ -1227,7 +1360,7 @@ func ReplaceDashboardCells(
}
defer s.DeleteDashboard(ctx, tt.args.dashboardID)
dashboards, _, err := s.FindDashboards(ctx, platform.DashboardFilter{})
dashboards, _, err := s.FindDashboards(ctx, platform.DashboardFilter{}, platform.DefaultDashboardFindOptions)
if err != nil {
t.Fatalf("failed to retrieve dashboards: %v", err)
}