diff --git a/GNUmakefile b/GNUmakefile new file mode 100644 index 0000000..1a70a64 --- /dev/null +++ b/GNUmakefile @@ -0,0 +1,33 @@ +TEST?=$$(go list ./... |grep -v 'vendor') +GOFMT_FILES?=$$(find . -name '*.go' |grep -v vendor) +PKG_NAME=github.com/nytm/go-grafana-api +GRAFANA_VERSION ?= latest +GO_VERSION ?= 1.10 +GRAFANA_CONTAINER_NAME ?= grafana-dev +GRAFANA_ADMIN_PWD ?= pwd4test + +default: test + +test: start-grafana test-in-local + +start-grafana: + CONTAINER_COUNT=$$(docker ps -a -f "Name=$(GRAFANA_CONTAINER_NAME)" | wc -l) ;\ + if [[ $$CONTAINER_COUNT -lt 1 ]]; then \ + docker run --name $(GRAFANA_CONTAINER_NAME) -d -p localhost:3000:3000 -e "GF_SECURITY_ADMIN_PASSWORD=$(GRAFANA_ADMIN_PWD)" "grafana/grafana:$(GRAFANA_VERSION)"; \ + else \ + docker start $(GRAFANA_CONTAINER_NAME) ;\ + fi \ + +test-in-local: + GRAFANA_AUTH=admin:$(GRAFANA_ADMIN_PWD) \ + go test \ + +test-in-docker: + docker run -it -v `pwd`:/go/src/$(PKG_NAME) \ + --link $$GRAFANA_CONTAINER_ID:grafana \ + --workdir /go/src/$(PKG_NAME) \ + -e "GRAFANA_AUTH=admin:$(GRAFANA_ADMIN_PWD)" \ + -e "GRAFANA_URL=http://grafana:3000" "golang:$(GO_VERSION)" go test + +fmt: + gofmt -w $(GOFMT_FILES) diff --git a/glide.lock b/glide.lock new file mode 100644 index 0000000..ef95f4c --- /dev/null +++ b/glide.lock @@ -0,0 +1,6 @@ +hash: 36e07f9b169213af00ef3c5d32f5fb5c5a6b149592de00f16819ae6ff52ca7e6 +updated: 2018-11-21T14:39:51.269588+08:00 +imports: [] +testImports: +- name: github.com/gobs/pretty + version: 09732c25a95b8e10e85177a3201cf4c7fe35a377 diff --git a/glide.yaml b/glide.yaml new file mode 100644 index 0000000..66ef23b --- /dev/null +++ b/glide.yaml @@ -0,0 +1,4 @@ +package: github.com/nytm/go-grafana-api +import: [] +testImport: +- package: github.com/gobs/pretty diff --git a/main_test.go b/main_test.go new file mode 100644 index 0000000..767227d --- /dev/null +++ b/main_test.go @@ -0,0 +1,25 @@ +package gapi + +import ( + "os" + "testing" +) + +var realClient *Client + +func TestMain(m *testing.M) { + var err error + grafanaAuth := os.Getenv("GRAFANA_AUTH") + grafanaUrl := os.Getenv("GRAFANA_URL") + if grafanaAuth == "" { + grafanaAuth = "admin:pwd4test" + } + if grafanaUrl == "" { + grafanaUrl = "http://localhost:3000" + } + realClient, err = New(grafanaAuth, grafanaUrl) + if err != nil { + panic(err) + } + m.Run() +} diff --git a/user_test.go b/user_test.go index dee1739..1643cd4 100644 --- a/user_test.go +++ b/user_test.go @@ -1,8 +1,9 @@ package gapi import ( - "github.com/gobs/pretty" "testing" + + "github.com/gobs/pretty" ) const ( @@ -11,25 +12,12 @@ const ( ) func TestUsers(t *testing.T) { - server, client := gapiTestTools(200, getUsersJSON) - defer server.Close() - - resp, err := client.Users() + resp, err := realClient.Users() if err != nil { t.Error(err) } - t.Log(pretty.PrettyFormat(resp)) - - user := User{ - Id: 1, - Email: "admin@localhost", - Name: "", - Login: "admin", - IsAdmin: true, - } - - if len(resp) != 1 || resp[0] != user { + if len(resp) == 0 { t.Error("Not correctly parsing returned users.") } } diff --git a/vendor/github.com/gobs/pretty/.gitignore b/vendor/github.com/gobs/pretty/.gitignore new file mode 100644 index 0000000..0026861 --- /dev/null +++ b/vendor/github.com/gobs/pretty/.gitignore @@ -0,0 +1,22 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe diff --git a/vendor/github.com/gobs/pretty/LICENSE b/vendor/github.com/gobs/pretty/LICENSE new file mode 100644 index 0000000..8ec4681 --- /dev/null +++ b/vendor/github.com/gobs/pretty/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) {{year}} {{fullname}} + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/gobs/pretty/README.md b/vendor/github.com/gobs/pretty/README.md new file mode 100644 index 0000000..6d1354e --- /dev/null +++ b/vendor/github.com/gobs/pretty/README.md @@ -0,0 +1,27 @@ +pretty +====== + +A Pretty-printer for Go data structures + +## Installation + + $ go get github.com/gobs/pretty + +## Documentation +http://godoc.org/github.com/gobs/pretty + +## Example + package main + + import "github.com/gobs/pretty" + + func main() { + stuff := map[string]interface{} { + "a": 1, + "b": "due", + "c": []int { 1, 2, 3 }, + "d": false, + } + + pretty.PrettyPrint(stuff) + } diff --git a/vendor/github.com/gobs/pretty/pretty.go b/vendor/github.com/gobs/pretty/pretty.go new file mode 100644 index 0000000..f691b9e --- /dev/null +++ b/vendor/github.com/gobs/pretty/pretty.go @@ -0,0 +1,186 @@ +/* + Pretty-print Go data structures +*/ +package pretty + +import ( + "bytes" + "fmt" + "io" + "os" + r "reflect" + "strconv" + "strings" +) + +const ( + DEFAULT_INDENT = " " + DEFAULT_NIL = "nil" +) + +// The context for printing +type Pretty struct { + // indent string + Indent string + // output recipient + Out io.Writer + // string for nil + NilString string + // compact empty array and struct + Compact bool + // Maximum nesting level + MaxLevel int +} + +// pretty print the input value (to stdout) +func PrettyPrint(i interface{}) { + PrettyPrintTo(os.Stdout, i, true) +} + +// pretty print the input value (to a string) +func PrettyFormat(i interface{}) string { + var out bytes.Buffer + PrettyPrintTo(&out, i, false) + return out.String() +} + +// pretty print the input value (to specified writer) +func PrettyPrintTo(out io.Writer, i interface{}, nl bool) { + p := &Pretty{Indent: DEFAULT_INDENT, Out: out, NilString: DEFAULT_NIL} + if nl { + p.Println(i) + } else { + p.Print(i) + } +} + +// pretty print the input value (no newline) +func (p *Pretty) Print(i interface{}) { + p.PrintValue(r.ValueOf(i), 0) +} + +// pretty print the input value (newline) +func (p *Pretty) Println(i interface{}) { + p.PrintValue(r.ValueOf(i), 0) + io.WriteString(p.Out, "\n") +} + +// recursively print the input value +func (p *Pretty) PrintValue(val r.Value, level int) { + if !val.IsValid() { + io.WriteString(p.Out, p.NilString) + return + } + + cur := strings.Repeat(p.Indent, level) + next := strings.Repeat(p.Indent, level+1) + + nl := "\n" + if len(p.Indent) == 0 { + nl = " " + } + + if p.MaxLevel > 0 && level >= p.MaxLevel { + io.WriteString(p.Out, val.String()) + return + } + + switch val.Kind() { + case r.Int, r.Int8, r.Int16, r.Int32, r.Int64: + io.WriteString(p.Out, strconv.FormatInt(val.Int(), 10)) + + case r.Uint, r.Uint8, r.Uint16, r.Uint32, r.Uint64: + io.WriteString(p.Out, strconv.FormatUint(val.Uint(), 10)) + + case r.Float32, r.Float64: + io.WriteString(p.Out, strconv.FormatFloat(val.Float(), 'f', -1, 64)) + + case r.String: + io.WriteString(p.Out, strconv.Quote(val.String())) + + case r.Bool: + io.WriteString(p.Out, strconv.FormatBool(val.Bool())) + + case r.Map: + l := val.Len() + + io.WriteString(p.Out, "{"+nl) + for i, k := range val.MapKeys() { + io.WriteString(p.Out, next) + io.WriteString(p.Out, strconv.Quote(k.String())) + io.WriteString(p.Out, ": ") + p.PrintValue(val.MapIndex(k), level+1) + if i < l-1 { + io.WriteString(p.Out, ","+nl) + } else { + io.WriteString(p.Out, nl) + } + } + io.WriteString(p.Out, cur) + io.WriteString(p.Out, "}") + + case r.Array, r.Slice: + l := val.Len() + + if p.Compact && l == 0 { + io.WriteString(p.Out, "[]") + } else { + io.WriteString(p.Out, "["+nl) + for i := 0; i < l; i++ { + io.WriteString(p.Out, next) + p.PrintValue(val.Index(i), level+1) + if i < l-1 { + io.WriteString(p.Out, ","+nl) + } else { + io.WriteString(p.Out, nl) + } + } + io.WriteString(p.Out, cur) + io.WriteString(p.Out, "]") + } + + case r.Interface, r.Ptr: + p.PrintValue(val.Elem(), level) + + case r.Struct: + if val.CanInterface() { + i := val.Interface() + if i, ok := i.(fmt.Stringer); ok { + io.WriteString(p.Out, i.String()) + } else { + l := val.NumField() + + sOpen := "struct {" + + if p.Compact { + sOpen = "{" + } + + if p.Compact && l == 0 { + io.WriteString(p.Out, "{}") + } else { + io.WriteString(p.Out, sOpen+nl) + for i := 0; i < l; i++ { + io.WriteString(p.Out, next) + io.WriteString(p.Out, val.Type().Field(i).Name) + io.WriteString(p.Out, ": ") + p.PrintValue(val.Field(i), level+1) + if i < l-1 { + io.WriteString(p.Out, ","+nl) + } else { + io.WriteString(p.Out, nl) + } + } + io.WriteString(p.Out, cur) + io.WriteString(p.Out, "}") + } + } + } else { + io.WriteString(p.Out, "protected") + } + + default: + io.WriteString(p.Out, "unsupported:") + io.WriteString(p.Out, val.String()) + } +} diff --git a/vendor/github.com/gobs/pretty/pretty_test.go b/vendor/github.com/gobs/pretty/pretty_test.go new file mode 100644 index 0000000..023263c --- /dev/null +++ b/vendor/github.com/gobs/pretty/pretty_test.go @@ -0,0 +1,140 @@ +package pretty + +import "bytes" +import "testing" + +type Bag map[string]interface{} + +type Struct struct { + N int + S string + B bool + A []int + Z []int +} + +var ( + ch chan string + + s = struct { + n int + s string + }{ + 42, + "hello world", + } + + x = struct{}{} + + arry = []Bag{bag, bag, bag} + + strutty = Struct{N: 42, S: "Hello", B: true, A: []int{1, 2, 3}} + + bag = Bag{ + "a": 1, + "b": false, + "c": "some stuff", + "d": []float64{0.0, 0.1, 1.2, 1.23, 1.23456, 999999999999}, + "e": Bag{ + "e1": "here", + "e2": []int{1, 2, 3, 4}, + "e3": nil, + "e4": s, + }, + "s": s, + "x": x, + "z": []int{}, + "bad": ch, + } +) + +func TestPrettyPrint(test *testing.T) { + PrettyPrint(arry) +} + +func TestPrettyFormat(test *testing.T) { + test.Log(PrettyFormat(bag)) +} + +func TestStruct(test *testing.T) { + test.Log(PrettyFormat(strutty)) +} + +func TestPretty(test *testing.T) { + var out bytes.Buffer + p := Pretty{Indent: "", Out: &out, NilString: "nil"} + p.Print(strutty) + test.Log(out.String()) +} + +func TestPrettyCompact(test *testing.T) { + var out bytes.Buffer + p := Pretty{Indent: "", Out: &out, NilString: "nil", Compact: true} + p.Print(strutty) + test.Log(out.String()) +} + +func TestPrettyLevel(test *testing.T) { + var out bytes.Buffer + p := Pretty{Indent: "", Out: &out, NilString: "nil", Compact: true, MaxLevel: 2} + p.Print(bag) + test.Log(out.String()) +} + +func ExampleTabPrint() { + tp := NewTabPrinter(8) + + for i := 0; i < 33; i++ { + tp.Print(i) + } + + tp.Println() + + for _, v := range []string{"one", "two", "three", "four", "five", "six"} { + tp.Print(v) + } + + tp.Println() + + // Output: + // 0 1 2 3 4 5 6 7 + // 8 9 10 11 12 13 14 15 + // 16 17 18 19 20 21 22 23 + // 24 25 26 27 28 29 30 31 + // 32 + // one two three four five six +} + +func ExampleTabPrintTwoFullLines() { + tp := NewTabPrinter(4) + + for _, v := range []string{"one", "two", "three", "four", "five", "six", "seven", "eight"} { + tp.Print(v) + } + + tp.Println() + + // Output: + // one two three four + // five six seven eight + // +} + +func ExampleTabPrintWider() { + tp := NewTabPrinter(2) + tp.TabWidth(10) + + for _, v := range []string{"one", "two", "three", "four", "five", "six", "seven", "eight", "larger", "largest", "even more", "enough"} { + tp.Print(v) + } + + tp.Println() + + // Output: + // one two + // three four + // five six + // seven eight + // larger largest + // even more enough +} diff --git a/vendor/github.com/gobs/pretty/tabprinter.go b/vendor/github.com/gobs/pretty/tabprinter.go new file mode 100644 index 0000000..b930309 --- /dev/null +++ b/vendor/github.com/gobs/pretty/tabprinter.go @@ -0,0 +1,60 @@ +package pretty + +import ( + "fmt" + "os" + "text/tabwriter" +) + +// A TabPrinter is an object that allows printing tab-aligned words on multiple lines, +// up to a maximum number per line +type TabPrinter struct { + w *tabwriter.Writer + current, max int +} + +// create a TabPrinter +// +// max specifies the maximum number of 'words' per line +func NewTabPrinter(max int) *TabPrinter { + tp := &TabPrinter{w: new(tabwriter.Writer), max: max} + tp.w.Init(os.Stdout, 0, 8, 1, '\t', 0) + + return tp +} + +// update tab width (minimal space between words) +// +func (tp *TabPrinter) TabWidth(n int) { + tp.w.Init(os.Stdout, n, 0, 1, ' ', 0) +} + +// print a 'word' +// +// when the maximum number of words per lines is reached, this will print the formatted line +func (tp *TabPrinter) Print(arg interface{}) { + if tp.current > 0 { + if (tp.current % tp.max) == 0 { + fmt.Fprintln(tp.w, "") + tp.w.Flush() + tp.current = 0 + } else { + fmt.Fprint(tp.w, "\t") + } + } + + tp.current++ + fmt.Fprint(tp.w, arg) +} + +// print current line +// +// terminate current line and print - call this after all words have been printed +func (tp *TabPrinter) Println() { + if tp.current > 0 { + fmt.Fprintln(tp.w, "") + tp.w.Flush() + } + + tp.current = 0 +}