From fdf2e62a43ebc8a88895baa833692dad269f9998 Mon Sep 17 00:00:00 2001 From: Vladimir Kononov Date: Wed, 29 Apr 2020 23:37:58 +0300 Subject: [PATCH 1/6] Add SearchWithParams method --- rest-dashboard.go | 116 ++++++++++++++++++++++ rest-dashboard_integration_test.go | 4 + rest-dashboard_test.go | 149 +++++++++++++++++++++++++++++ 3 files changed, 269 insertions(+) create mode 100644 rest-dashboard_test.go diff --git a/rest-dashboard.go b/rest-dashboard.go index ec7c7870..14e78e78 100644 --- a/rest-dashboard.go +++ b/rest-dashboard.go @@ -25,6 +25,7 @@ import ( "encoding/json" "fmt" "net/url" + "strconv" "strings" "time" @@ -170,6 +171,8 @@ type FoundBoard struct { // only starred dashboards and only for tags (logical OR applied to multiple tags). // // Reflects GET /api/search API call. +// Deprecated: This interface does not allow for API extension and is out of date. +// Please use SearchWithParams(WithSearchType(SearchTypeDashboard)) func (r *Client) SearchDashboards(ctx context.Context, query string, starred bool, tags ...string) ([]FoundBoard, error) { var ( raw []byte @@ -198,6 +201,31 @@ func (r *Client) SearchDashboards(ctx context.Context, query string, starred boo return boards, err } +// SearchWithParams searches folders and dashboards with query params specified. +// +// Reflects GET /api/search API call. +func (r *Client) SearchWithParams(ctx context.Context, params ...SearchParam) ([]FoundBoard, error) { + var ( + raw []byte + boards []FoundBoard + code int + err error + ) + u := url.URL{} + q := u.Query() + for _, p := range params { + p(&q) + } + if raw, code, err = r.get(ctx, "api/search", q); err != nil { + return nil, err + } + if code != 200 { + return nil, fmt.Errorf("HTTP error %d: returns %s", code, raw) + } + err = json.Unmarshal(raw, &boards) + return boards, err +} + // SetDashboardParams contains the extra parameteres // that affects where and how the dashboard will be stored type SetDashboardParams struct { @@ -308,6 +336,94 @@ func (r *Client) DeleteDashboard(ctx context.Context, slug string) (StatusMessag return reply, err } +type ( + // SearchParam is a type for specifying SearchWithParams params. + SearchParam func(*url.Values) + // SearchType is a type accepted by WithSearchType func. + SearchType string +) + +var ( + SearchTypeFolder SearchType = "dash-folder" + SearchTypeDashboard SearchType = "dash-db" +) + +// WithSearchQuery specifies SearchWithParams search query. +// Empty query is silently ignored. +// Specifying it multiple times is futile, only last one will be sent. +func WithSearchQuery(query string) SearchParam { + return func(v *url.Values) { + if query != "" { + v.Set("query", query) + } + } +} + +// WithSearchTag specifies SearchWithParams tag to search for. +// Empty tag is silently ignored. +// Can be specified multiple times, logical OR is applied. +func WithSearchTag(tag string) SearchParam { + return func(v *url.Values) { + if tag != "" { + v.Add("tag", tag) + } + } +} + +// WithSearchType specifies SearchWithParams type to search for. +// Specifying it multiple times is futile, only last one will be sent. +func WithSearchType(searchType SearchType) SearchParam { + return func(v *url.Values) { + v.Set("type", string(searchType)) + } +} + +// WithSearchDashboardID specifies SearchWithParams dashboard id's to search for. +// Can be specified multiple times, logical OR is applied. +func WithSearchDashboardID(dashboardID int) SearchParam { + return func(v *url.Values) { + v.Add("dashboardIds", strconv.Itoa(dashboardID)) + } +} + +// WithSearchFolderID specifies SearchWithParams folder id's to search for. +// Can be specified multiple times, logical OR is applied. +func WithSearchFolderID(folderID int) SearchParam { + return func(v *url.Values) { + v.Add("folderIds", strconv.Itoa(folderID)) + } +} + +// WithSearchStarred specifies if SearchWithParams should search for starred dashboards only. +// Specifying it multiple times is futile, only last one will be sent. +func WithSearchStarred(starred bool) SearchParam { + return func(v *url.Values) { + v.Set("starred", strconv.FormatBool(starred)) + } +} + +// WithSearchLimit specifies maximum number of results from SearchWithParams query. +// As of grafana 6.7 it has to be <= 5000. 0 stands for absence of parameter in a query. +// Specifying it multiple times is futile, only last one will be sent. +func WithSearchLimit(limit uint) SearchParam { + return func(v *url.Values) { + if limit > 0 { + v.Set("limit", strconv.FormatUint(uint64(limit), 10)) + } + } +} + +// WithSearchPage specifies SearchWithParams page number to be queried for. +// Zero page is silently ignored, page numbers start from one. +// Specifying it multiple times is futile, only last one will be sent. +func WithSearchPage(page uint) SearchParam { + return func(v *url.Values) { + if page > 0 { + v.Set("page", strconv.FormatUint(uint64(page), 10)) + } + } +} + // implicitly use dashboards from Grafana DB not from a file system func setPrefix(slug string) string { if strings.HasPrefix(slug, "db") { diff --git a/rest-dashboard_integration_test.go b/rest-dashboard_integration_test.go index 1deced44..c9beb0e1 100644 --- a/rest-dashboard_integration_test.go +++ b/rest-dashboard_integration_test.go @@ -42,6 +42,10 @@ func Test_Dashboard_CRUD(t *testing.T) { t.Fatal(err) } + if boardLinks, err = client.SearchWithParams(ctx, sdk.WithSearchStarred(false)); err != nil { + t.Fatal(err) + } + for _, link := range boardLinks { _, _, err = client.GetDashboardByUID(ctx, link.UID) if err != nil { diff --git a/rest-dashboard_test.go b/rest-dashboard_test.go new file mode 100644 index 00000000..c0edfbad --- /dev/null +++ b/rest-dashboard_test.go @@ -0,0 +1,149 @@ +package sdk_test + +import ( + "net/url" + "strconv" + "testing" + + "github.com/grafana-tools/sdk" +) + +func TestWithSearchQuery(t *testing.T) { + testStringSearchParam(t, sdk.WithSearchQuery, "query", []string{"foo", "bar"}) +} + +func TestWithSearchTag(t *testing.T) { + testRepeatableStringSearchParam(t, sdk.WithSearchTag, "tag", []string{"foo", "bar"}) +} + +func TestWithSearchDashboardID(t *testing.T) { + testRepeatableIntSearchParam(t, sdk.WithSearchDashboardID, "dashboardIds", []int{100, 200}) +} + +func TestWithSearchFolderID(t *testing.T) { + testRepeatableIntSearchParam(t, sdk.WithSearchFolderID, "folderIds", []int{100, 200}) +} + +func TestWithSearchPage(t *testing.T) { + testNonZeroUIntSearchParam(t, sdk.WithSearchPage, "page", []uint{100, 200}) +} + +func TestWithSearchLimit(t *testing.T) { + testNonZeroUIntSearchParam(t, sdk.WithSearchLimit, "limit", []uint{100, 200}) +} + +func TestWithSearchStarred(t *testing.T) { + testBoolSearchParam(t, sdk.WithSearchStarred, "starred", []bool{true, false}) +} + +func TestWithSearchType(t *testing.T) { + var ( + sp = sdk.WithSearchType + key = "type" + testValues = []sdk.SearchType{"foo", "bar"} + ) + + v := make(url.Values) + for _, testValue := range testValues { + sp(testValue)(&v) + expectedLen := 1 + gotLen := len(v[key]) + if gotLen != expectedLen { + t.Errorf("expected length of %s to be %d, but was %d", key, expectedLen, gotLen) + } + value := v.Get(key) + if value != string(testValue) { + t.Errorf("expected value of %s to be %s, but was %s", key, testValue, value) + } + } +} + +func testRepeatableStringSearchParam(t *testing.T, sp func(string) sdk.SearchParam, key string, testValues []string) { + v := make(url.Values) + for i, testValue := range testValues { + sp(testValue)(&v) + expectedLen := i + 1 + gotLen := len(v[key]) + if gotLen != expectedLen { + t.Errorf("expected length of %s to be %d, but was %d", key, expectedLen, gotLen) + } + last := v[key][i] + if last != testValue { + t.Errorf("expected last %s to be %s, but was %s", key, testValue, last) + } + } +} + +func testStringSearchParam(t *testing.T, sp func(string) sdk.SearchParam, key string, testValues []string) { + v := make(url.Values) + for _, testValue := range testValues { + sp(testValue)(&v) + expectedLen := 1 + gotLen := len(v[key]) + if gotLen != expectedLen { + t.Errorf("expected length of %s to be %d, but was %d", key, expectedLen, gotLen) + } + value := v.Get(key) + if value != testValue { + t.Errorf("expected value of %s to be %s, but was %s", key, testValue, value) + } + } +} + +func testBoolSearchParam(t *testing.T, sp func(bool) sdk.SearchParam, key string, testValues []bool) { + v := make(url.Values) + for _, testValue := range testValues { + sp(testValue)(&v) + expectedLen := 1 + gotLen := len(v[key]) + if gotLen != expectedLen { + t.Errorf("expected length of %s to be %d, but was %d", key, expectedLen, gotLen) + } + value := v.Get(key) + if value != strconv.FormatBool(testValue) { + t.Errorf("expected value of %s to be %t, but was %s", key, testValue, value) + } + } +} + +func testRepeatableIntSearchParam(t *testing.T, sp func(int) sdk.SearchParam, key string, testValues []int) { + v := make(url.Values) + for i, testValue := range testValues { + sp(testValue)(&v) + expectedLen := i + 1 + gotLen := len(v[key]) + if gotLen != expectedLen { + t.Errorf("expected length of %s to be %d, but was %d", key, expectedLen, gotLen) + } + last := v[key][i] + if last != strconv.Itoa(testValue) { + t.Errorf("expected last %s to be %d, but was %s", key, testValue, last) + } + } +} + +func testNonZeroUIntSearchParam(t *testing.T, sp func(uint) sdk.SearchParam, key string, testValues []uint) { + v := make(url.Values) + sp(0)(&v) + value := v.Get(key) + if value != "" { + t.Errorf("expected value of %s to be unset, but was %s", key, value) + } + testUIntSearchParam(t, sp, key, testValues) +} + +func testUIntSearchParam(t *testing.T, sp func(uint) sdk.SearchParam, key string, testValues []uint) { + v := make(url.Values) + for _, testValue := range testValues { + sp(testValue)(&v) + expectedLen := 1 + gotLen := len(v[key]) + if gotLen != expectedLen { + t.Errorf("expected length of %s to be %d, but was %d", key, expectedLen, gotLen) + } + value := v.Get(key) + if value != strconv.FormatUint(uint64(testValue), 10) { + t.Errorf("expected value of %s to be %d, but was %s", key, testValue, value) + } + } +} From 7e0012ab119f654080c681cf9c674fe0ff93b84a Mon Sep 17 00:00:00 2001 From: Vladimir Kononov Date: Mon, 4 May 2020 19:43:18 +0300 Subject: [PATCH 2/6] Make exported SearchType const instead of var --- rest-dashboard.go | 2 +- rest-dashboard_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rest-dashboard.go b/rest-dashboard.go index 14e78e78..3e537f36 100644 --- a/rest-dashboard.go +++ b/rest-dashboard.go @@ -343,7 +343,7 @@ type ( SearchType string ) -var ( +const ( SearchTypeFolder SearchType = "dash-folder" SearchTypeDashboard SearchType = "dash-db" ) diff --git a/rest-dashboard_test.go b/rest-dashboard_test.go index c0edfbad..75ca2387 100644 --- a/rest-dashboard_test.go +++ b/rest-dashboard_test.go @@ -40,7 +40,7 @@ func TestWithSearchType(t *testing.T) { var ( sp = sdk.WithSearchType key = "type" - testValues = []sdk.SearchType{"foo", "bar"} + testValues = []sdk.SearchType{sdk.SearchTypeFolder, sdk.SearchTypeDashboard} ) v := make(url.Values) From b286e800862a43e3e70598863d41f2ceab366a03 Mon Sep 17 00:00:00 2001 From: Vladimir Kononov Date: Mon, 4 May 2020 19:44:41 +0300 Subject: [PATCH 3/6] Refactor SearchDashboards --- rest-dashboard.go | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/rest-dashboard.go b/rest-dashboard.go index 3e537f36..1e0ef552 100644 --- a/rest-dashboard.go +++ b/rest-dashboard.go @@ -174,31 +174,15 @@ type FoundBoard struct { // Deprecated: This interface does not allow for API extension and is out of date. // Please use SearchWithParams(WithSearchType(SearchTypeDashboard)) func (r *Client) SearchDashboards(ctx context.Context, query string, starred bool, tags ...string) ([]FoundBoard, error) { - var ( - raw []byte - boards []FoundBoard - code int - err error - ) - u := url.URL{} - q := u.Query() - if query != "" { - q.Set("query", query) - } - if starred { - q.Set("starred", "true") + params := []SearchParam{ + WithSearchType(SearchTypeDashboard), + WithSearchQuery(query), + WithSearchStarred(starred), } for _, tag := range tags { - q.Add("tag", tag) + params = append(params, WithSearchTag(tag)) } - if raw, code, err = r.get(ctx, "api/search", q); err != nil { - return nil, err - } - if code != 200 { - return nil, fmt.Errorf("HTTP error %d: returns %s", code, raw) - } - err = json.Unmarshal(raw, &boards) - return boards, err + return r.SearchWithParams(ctx, params...) } // SearchWithParams searches folders and dashboards with query params specified. From 3b89d996f7985753ad710bfb60f9b1d2473dc3d4 Mon Sep 17 00:00:00 2001 From: Vladimir Kononov Date: Mon, 4 May 2020 19:50:28 +0300 Subject: [PATCH 4/6] Add missed comment for SearchType constants --- rest-dashboard.go | 1 + 1 file changed, 1 insertion(+) diff --git a/rest-dashboard.go b/rest-dashboard.go index 1e0ef552..5e416bbf 100644 --- a/rest-dashboard.go +++ b/rest-dashboard.go @@ -327,6 +327,7 @@ type ( SearchType string ) +// Search entities to be used with WithSearchType(). const ( SearchTypeFolder SearchType = "dash-folder" SearchTypeDashboard SearchType = "dash-db" From c9dec7c74d88b8d83fdd44391b54200851065861 Mon Sep 17 00:00:00 2001 From: Vladimir Kononov Date: Tue, 5 May 2020 18:25:06 +0300 Subject: [PATCH 5/6] Add unit tests for SearchDashboards and SearchWithParams --- rest-dashboard_integration_test.go | 7 +- rest-dashboard_test.go | 136 +++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+), 3 deletions(-) diff --git a/rest-dashboard_integration_test.go b/rest-dashboard_integration_test.go index c9beb0e1..34258ff5 100644 --- a/rest-dashboard_integration_test.go +++ b/rest-dashboard_integration_test.go @@ -20,6 +20,7 @@ func Test_Dashboard_CRUD(t *testing.T) { client := getClient(t) var board sdk.Board + raw, _ := ioutil.ReadFile("testdata/new-empty-dashboard-2.6.json") if err = json.Unmarshal(raw, &board); err != nil { @@ -38,12 +39,12 @@ func Test_Dashboard_CRUD(t *testing.T) { t.Fatal(err) } - if boardLinks, err = client.SearchDashboards(ctx, "", false); err != nil { + if boardLinks, err = client.SearchWithParams(ctx, sdk.WithSearchType(sdk.SearchTypeDashboard)); err != nil { t.Fatal(err) } - if boardLinks, err = client.SearchWithParams(ctx, sdk.WithSearchStarred(false)); err != nil { - t.Fatal(err) + if len(boardLinks) == 0 { + t.Fatal("search query returned empty dashboard list") } for _, link := range boardLinks { diff --git a/rest-dashboard_test.go b/rest-dashboard_test.go index 75ca2387..b4304338 100644 --- a/rest-dashboard_test.go +++ b/rest-dashboard_test.go @@ -1,13 +1,149 @@ package sdk_test import ( + "context" + "net/http" + "net/http/httptest" "net/url" + "reflect" "strconv" "testing" "github.com/grafana-tools/sdk" ) +func TestClient_SearchDashboards(t *testing.T) { + type in struct { + Query string + Starred bool + Tags []string + } + type testCase struct { + In in + Out url.Values + } + dashboard := string(sdk.SearchTypeDashboard) + for i, tc := range []testCase{ + { + In: in{}, + Out: url.Values{"type": []string{dashboard}, "starred": []string{"false"}}, + }, + { + In: in{Starred: true}, + Out: url.Values{"type": []string{dashboard}, "starred": []string{"true"}}, + }, + { + In: in{Query: "Foo"}, + Out: url.Values{"type": []string{dashboard}, "query": []string{"Foo"}, "starred": []string{"false"}}, + }, + { + In: in{Tags: []string{"Foo", "Bar"}}, + Out: url.Values{"type": []string{dashboard}, "starred": []string{"false"}, "tag": []string{"Foo", "Bar"}}, + }, + } { + ts := httptest.NewServer(http.HandlerFunc(testSearchQuery(t, i, tc.Out))) + client := sdk.NewClient(ts.URL, "", ts.Client()) + ctx := context.Background() + _, err := client.SearchDashboards(ctx, tc.In.Query, tc.In.Starred, tc.In.Tags...) + ts.Close() + if err != nil { + t.Fatalf("SearchDashboards test %d failed: %s", i, err) + } + } +} + +func TestClient_SearchWithParams(t *testing.T) { + type testCase struct { + In []sdk.SearchParam + Out url.Values + } + for i, tc := range []testCase{ + { + In: []sdk.SearchParam{}, + Out: url.Values{}, + }, + { + // Test all options given their correct usage. + In: []sdk.SearchParam{ + sdk.WithSearchDashboardID(234), + sdk.WithSearchDashboardID(432), + sdk.WithSearchFolderID(123), + sdk.WithSearchFolderID(321), + sdk.WithSearchLimit(10), + sdk.WithSearchPage(99), + sdk.WithSearchQuery("Q"), + sdk.WithSearchStarred(true), + sdk.WithSearchTag("Foo"), + sdk.WithSearchTag("Bar"), + sdk.WithSearchType(sdk.SearchTypeFolder), + }, + Out: url.Values{ + "dashboardIds": []string{"234", "432"}, + "folderIds": []string{"123", "321"}, + "limit": []string{"10"}, + "page": []string{"99"}, + "query": []string{"Q"}, + "starred": []string{"true"}, + "tag": []string{"Foo", "Bar"}, + "type": []string{string(sdk.SearchTypeFolder)}, + }, + }, + { + // Test non-repeatable options. + In: []sdk.SearchParam{ + sdk.WithSearchLimit(10), + sdk.WithSearchLimit(100), + sdk.WithSearchPage(88), + sdk.WithSearchPage(99), + sdk.WithSearchQuery("Q1"), + sdk.WithSearchQuery("Q2"), + sdk.WithSearchStarred(true), + sdk.WithSearchStarred(false), + sdk.WithSearchType(sdk.SearchTypeFolder), + sdk.WithSearchType(sdk.SearchTypeDashboard), + }, + Out: url.Values{ + "limit": []string{"100"}, + "page": []string{"99"}, + "query": []string{"Q2"}, + "starred": []string{"false"}, + "type": []string{string(sdk.SearchTypeDashboard)}, + }, + }, + } { + ts := httptest.NewServer(http.HandlerFunc(testSearchQuery(t, i, tc.Out))) + client := sdk.NewClient(ts.URL, "", ts.Client()) + ctx := context.Background() + _, err := client.SearchWithParams(ctx, tc.In...) + ts.Close() + if err != nil { + t.Fatalf("SearchDashboards test %d failed: %s", i, err) + } + + } +} + +func testSearchQuery(t *testing.T, testID int, exp url.Values) func(w http.ResponseWriter, r *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + if m := r.Method; m != http.MethodGet { + t.Fatalf("unexpected http method for case %d: expected %s, got %s", testID, http.MethodGet, m) + } + if e := "/api/search"; r.URL.Path != e { + t.Fatalf("unexpected http handler called for case %d: expected %s, got %s", testID, r.URL.Path, e) + } + qv, err := url.ParseQuery(r.URL.RawQuery) + if err != nil { + t.Fatalf("failed to parse query for case %d: %s, got err %s", testID, r.URL.RawQuery, err) + } + if !reflect.DeepEqual(exp, qv) { + t.Fatalf("unexpected query arguments for case %d: expected %v, got %v", testID, exp, qv) + } + if _, err := w.Write([]byte("[]")); err != nil { + t.Fatalf("failed to write http answer for case %d: %s", testID, err) + } + } +} + func TestWithSearchQuery(t *testing.T) { testStringSearchParam(t, sdk.WithSearchQuery, "query", []string{"foo", "bar"}) } From 0dca3a1d62b1c6e6df74e7d99a9d29d1157d8611 Mon Sep 17 00:00:00 2001 From: Vladimir Kononov Date: Wed, 6 May 2020 11:09:34 +0300 Subject: [PATCH 6/6] Simplify search-related names --- rest-dashboard.go | 60 +++++++++++----------- rest-dashboard_integration_test.go | 2 +- rest-dashboard_test.go | 80 +++++++++++++++--------------- 3 files changed, 71 insertions(+), 71 deletions(-) diff --git a/rest-dashboard.go b/rest-dashboard.go index 5e416bbf..3a77c8f8 100644 --- a/rest-dashboard.go +++ b/rest-dashboard.go @@ -172,23 +172,23 @@ type FoundBoard struct { // // Reflects GET /api/search API call. // Deprecated: This interface does not allow for API extension and is out of date. -// Please use SearchWithParams(WithSearchType(SearchTypeDashboard)) +// Please use Search(SearchType(SearchTypeDashboard)) func (r *Client) SearchDashboards(ctx context.Context, query string, starred bool, tags ...string) ([]FoundBoard, error) { params := []SearchParam{ - WithSearchType(SearchTypeDashboard), - WithSearchQuery(query), - WithSearchStarred(starred), + SearchType(SearchTypeDashboard), + SearchQuery(query), + SearchStarred(starred), } for _, tag := range tags { - params = append(params, WithSearchTag(tag)) + params = append(params, SearchTag(tag)) } - return r.SearchWithParams(ctx, params...) + return r.Search(ctx, params...) } -// SearchWithParams searches folders and dashboards with query params specified. +// Search searches folders and dashboards with query params specified. // // Reflects GET /api/search API call. -func (r *Client) SearchWithParams(ctx context.Context, params ...SearchParam) ([]FoundBoard, error) { +func (r *Client) Search(ctx context.Context, params ...SearchParam) ([]FoundBoard, error) { var ( raw []byte boards []FoundBoard @@ -321,22 +321,22 @@ func (r *Client) DeleteDashboard(ctx context.Context, slug string) (StatusMessag } type ( - // SearchParam is a type for specifying SearchWithParams params. + // SearchParam is a type for specifying Search params. SearchParam func(*url.Values) - // SearchType is a type accepted by WithSearchType func. - SearchType string + // SearchParamType is a type accepted by SearchType func. + SearchParamType string ) -// Search entities to be used with WithSearchType(). +// Search entities to be used with SearchType(). const ( - SearchTypeFolder SearchType = "dash-folder" - SearchTypeDashboard SearchType = "dash-db" + SearchTypeFolder SearchParamType = "dash-folder" + SearchTypeDashboard SearchParamType = "dash-db" ) -// WithSearchQuery specifies SearchWithParams search query. +// SearchQuery specifies Search search query. // Empty query is silently ignored. // Specifying it multiple times is futile, only last one will be sent. -func WithSearchQuery(query string) SearchParam { +func SearchQuery(query string) SearchParam { return func(v *url.Values) { if query != "" { v.Set("query", query) @@ -344,10 +344,10 @@ func WithSearchQuery(query string) SearchParam { } } -// WithSearchTag specifies SearchWithParams tag to search for. +// SearchTag specifies Search tag to search for. // Empty tag is silently ignored. // Can be specified multiple times, logical OR is applied. -func WithSearchTag(tag string) SearchParam { +func SearchTag(tag string) SearchParam { return func(v *url.Values) { if tag != "" { v.Add("tag", tag) @@ -355,42 +355,42 @@ func WithSearchTag(tag string) SearchParam { } } -// WithSearchType specifies SearchWithParams type to search for. +// SearchType specifies Search type to search for. // Specifying it multiple times is futile, only last one will be sent. -func WithSearchType(searchType SearchType) SearchParam { +func SearchType(searchType SearchParamType) SearchParam { return func(v *url.Values) { v.Set("type", string(searchType)) } } -// WithSearchDashboardID specifies SearchWithParams dashboard id's to search for. +// SearchDashboardID specifies Search dashboard id's to search for. // Can be specified multiple times, logical OR is applied. -func WithSearchDashboardID(dashboardID int) SearchParam { +func SearchDashboardID(dashboardID int) SearchParam { return func(v *url.Values) { v.Add("dashboardIds", strconv.Itoa(dashboardID)) } } -// WithSearchFolderID specifies SearchWithParams folder id's to search for. +// SearchFolderID specifies Search folder id's to search for. // Can be specified multiple times, logical OR is applied. -func WithSearchFolderID(folderID int) SearchParam { +func SearchFolderID(folderID int) SearchParam { return func(v *url.Values) { v.Add("folderIds", strconv.Itoa(folderID)) } } -// WithSearchStarred specifies if SearchWithParams should search for starred dashboards only. +// SearchStarred specifies if Search should search for starred dashboards only. // Specifying it multiple times is futile, only last one will be sent. -func WithSearchStarred(starred bool) SearchParam { +func SearchStarred(starred bool) SearchParam { return func(v *url.Values) { v.Set("starred", strconv.FormatBool(starred)) } } -// WithSearchLimit specifies maximum number of results from SearchWithParams query. +// SearchLimit specifies maximum number of results from Search query. // As of grafana 6.7 it has to be <= 5000. 0 stands for absence of parameter in a query. // Specifying it multiple times is futile, only last one will be sent. -func WithSearchLimit(limit uint) SearchParam { +func SearchLimit(limit uint) SearchParam { return func(v *url.Values) { if limit > 0 { v.Set("limit", strconv.FormatUint(uint64(limit), 10)) @@ -398,10 +398,10 @@ func WithSearchLimit(limit uint) SearchParam { } } -// WithSearchPage specifies SearchWithParams page number to be queried for. +// SearchPage specifies Search page number to be queried for. // Zero page is silently ignored, page numbers start from one. // Specifying it multiple times is futile, only last one will be sent. -func WithSearchPage(page uint) SearchParam { +func SearchPage(page uint) SearchParam { return func(v *url.Values) { if page > 0 { v.Set("page", strconv.FormatUint(uint64(page), 10)) diff --git a/rest-dashboard_integration_test.go b/rest-dashboard_integration_test.go index 34258ff5..5637edb2 100644 --- a/rest-dashboard_integration_test.go +++ b/rest-dashboard_integration_test.go @@ -39,7 +39,7 @@ func Test_Dashboard_CRUD(t *testing.T) { t.Fatal(err) } - if boardLinks, err = client.SearchWithParams(ctx, sdk.WithSearchType(sdk.SearchTypeDashboard)); err != nil { + if boardLinks, err = client.Search(ctx, sdk.SearchType(sdk.SearchTypeDashboard)); err != nil { t.Fatal(err) } diff --git a/rest-dashboard_test.go b/rest-dashboard_test.go index b4304338..006d98a5 100644 --- a/rest-dashboard_test.go +++ b/rest-dashboard_test.go @@ -52,7 +52,7 @@ func TestClient_SearchDashboards(t *testing.T) { } } -func TestClient_SearchWithParams(t *testing.T) { +func TestClient_Search(t *testing.T) { type testCase struct { In []sdk.SearchParam Out url.Values @@ -65,17 +65,17 @@ func TestClient_SearchWithParams(t *testing.T) { { // Test all options given their correct usage. In: []sdk.SearchParam{ - sdk.WithSearchDashboardID(234), - sdk.WithSearchDashboardID(432), - sdk.WithSearchFolderID(123), - sdk.WithSearchFolderID(321), - sdk.WithSearchLimit(10), - sdk.WithSearchPage(99), - sdk.WithSearchQuery("Q"), - sdk.WithSearchStarred(true), - sdk.WithSearchTag("Foo"), - sdk.WithSearchTag("Bar"), - sdk.WithSearchType(sdk.SearchTypeFolder), + sdk.SearchDashboardID(234), + sdk.SearchDashboardID(432), + sdk.SearchFolderID(123), + sdk.SearchFolderID(321), + sdk.SearchLimit(10), + sdk.SearchPage(99), + sdk.SearchQuery("Q"), + sdk.SearchStarred(true), + sdk.SearchTag("Foo"), + sdk.SearchTag("Bar"), + sdk.SearchType(sdk.SearchTypeFolder), }, Out: url.Values{ "dashboardIds": []string{"234", "432"}, @@ -91,16 +91,16 @@ func TestClient_SearchWithParams(t *testing.T) { { // Test non-repeatable options. In: []sdk.SearchParam{ - sdk.WithSearchLimit(10), - sdk.WithSearchLimit(100), - sdk.WithSearchPage(88), - sdk.WithSearchPage(99), - sdk.WithSearchQuery("Q1"), - sdk.WithSearchQuery("Q2"), - sdk.WithSearchStarred(true), - sdk.WithSearchStarred(false), - sdk.WithSearchType(sdk.SearchTypeFolder), - sdk.WithSearchType(sdk.SearchTypeDashboard), + sdk.SearchLimit(10), + sdk.SearchLimit(100), + sdk.SearchPage(88), + sdk.SearchPage(99), + sdk.SearchQuery("Q1"), + sdk.SearchQuery("Q2"), + sdk.SearchStarred(true), + sdk.SearchStarred(false), + sdk.SearchType(sdk.SearchTypeFolder), + sdk.SearchType(sdk.SearchTypeDashboard), }, Out: url.Values{ "limit": []string{"100"}, @@ -114,7 +114,7 @@ func TestClient_SearchWithParams(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(testSearchQuery(t, i, tc.Out))) client := sdk.NewClient(ts.URL, "", ts.Client()) ctx := context.Background() - _, err := client.SearchWithParams(ctx, tc.In...) + _, err := client.Search(ctx, tc.In...) ts.Close() if err != nil { t.Fatalf("SearchDashboards test %d failed: %s", i, err) @@ -144,39 +144,39 @@ func testSearchQuery(t *testing.T, testID int, exp url.Values) func(w http.Respo } } -func TestWithSearchQuery(t *testing.T) { - testStringSearchParam(t, sdk.WithSearchQuery, "query", []string{"foo", "bar"}) +func TestSearchQuery(t *testing.T) { + testStringSearchParam(t, sdk.SearchQuery, "query", []string{"foo", "bar"}) } -func TestWithSearchTag(t *testing.T) { - testRepeatableStringSearchParam(t, sdk.WithSearchTag, "tag", []string{"foo", "bar"}) +func TestSearchTag(t *testing.T) { + testRepeatableStringSearchParam(t, sdk.SearchTag, "tag", []string{"foo", "bar"}) } -func TestWithSearchDashboardID(t *testing.T) { - testRepeatableIntSearchParam(t, sdk.WithSearchDashboardID, "dashboardIds", []int{100, 200}) +func TestSearchDashboardID(t *testing.T) { + testRepeatableIntSearchParam(t, sdk.SearchDashboardID, "dashboardIds", []int{100, 200}) } -func TestWithSearchFolderID(t *testing.T) { - testRepeatableIntSearchParam(t, sdk.WithSearchFolderID, "folderIds", []int{100, 200}) +func TestSearchFolderID(t *testing.T) { + testRepeatableIntSearchParam(t, sdk.SearchFolderID, "folderIds", []int{100, 200}) } -func TestWithSearchPage(t *testing.T) { - testNonZeroUIntSearchParam(t, sdk.WithSearchPage, "page", []uint{100, 200}) +func TestSearchPage(t *testing.T) { + testNonZeroUIntSearchParam(t, sdk.SearchPage, "page", []uint{100, 200}) } -func TestWithSearchLimit(t *testing.T) { - testNonZeroUIntSearchParam(t, sdk.WithSearchLimit, "limit", []uint{100, 200}) +func TestSearchLimit(t *testing.T) { + testNonZeroUIntSearchParam(t, sdk.SearchLimit, "limit", []uint{100, 200}) } -func TestWithSearchStarred(t *testing.T) { - testBoolSearchParam(t, sdk.WithSearchStarred, "starred", []bool{true, false}) +func TestSearchStarred(t *testing.T) { + testBoolSearchParam(t, sdk.SearchStarred, "starred", []bool{true, false}) } -func TestWithSearchType(t *testing.T) { +func TestSearchType(t *testing.T) { var ( - sp = sdk.WithSearchType + sp = sdk.SearchType key = "type" - testValues = []sdk.SearchType{sdk.SearchTypeFolder, sdk.SearchTypeDashboard} + testValues = []sdk.SearchParamType{sdk.SearchTypeFolder, sdk.SearchTypeDashboard} ) v := make(url.Values)