Skip to content

Commit

Permalink
Allow evaluating of individual expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinjqiu committed Aug 3, 2018
1 parent f1c885e commit 8e0926f
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 49 deletions.
104 changes: 88 additions & 16 deletions _proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@ package promql

import (
"log"
"github.com/prometheus/prometheus/storage"
"github.com/prometheus/prometheus/util/testutil"
"fmt"
"time"
"golang.org/x/net/context"
)

type TestCommand = testCommand
Expand All @@ -32,21 +30,95 @@ func ParseTestCommand(input string) ([]TestCommand, error) {
return t.cmds, nil
}

func ExecuteTestCommand(tc TestCommand, storage *storage.Storage) (*storage.Storage, error) {
t := Test{
T: t{},
storage: *storage,
cmds: []TestCommand{tc},
type TestShell struct {
Test Test
}

func (ts *TestShell) SetCmds(cmds []TestCommand) {
ts.Test.cmds = cmds
}

func (ts *TestShell) Run() error {
for _, cmd := range ts.Test.cmds {
err := ts.exec(cmd)
if err != nil {
return err // TODO: use multi-error
}
}
t.queryEngine = NewEngine(nil, nil, 20, 10*time.Second)
t.context, t.cancelCtx = context.WithCancel(context.Background())
return &t.storage, t.exec(tc)
return nil
}

func NewTestStorage() *storage.Storage {
t := Test{
T: t{},
func (ts *TestShell) exec(tc testCommand) error {
switch cmd := tc.(type) {
case *evalCmd:
t := ts.Test
q, _ := t.queryEngine.NewInstantQuery(t.storage, cmd.expr, cmd.start)
res := q.Exec(t.context)
if res.Err != nil {
if cmd.fail {
return nil
}
return fmt.Errorf("error evaluating query %q: %s", cmd.expr, res.Err)
}
defer q.Close()
if res.Err == nil && cmd.fail {
return fmt.Errorf("expected error evaluating query but got none")
}

if len(cmd.expected) == 0 {
fmt.Println(res.Value)
return nil
}
err := cmd.compareResult(res.Value)
if err != nil {
return fmt.Errorf("error in %s %s: %s", cmd, cmd.expr, err)
}

// Check query returns same result in range mode,
/// by checking against the middle step.
q, _ = t.queryEngine.NewRangeQuery(t.storage, cmd.expr, cmd.start.Add(-time.Minute), cmd.start.Add(time.Minute), time.Minute)
rangeRes := q.Exec(t.context)
if rangeRes.Err != nil {
return fmt.Errorf("error evaluating query %q in range mode: %s", cmd.expr, rangeRes.Err)
}
defer q.Close()
if cmd.ordered {
// Ordering isn't defined for range queries.
return nil
}
mat := rangeRes.Value.(Matrix)
vec := make(Vector, 0, len(mat))
for _, series := range mat {
for _, point := range series.Points {
if point.T == timeMilliseconds(cmd.start) {
vec = append(vec, Sample{Metric: series.Metric, Point: point})
break
}
}
}
if len(cmd.expected) == 0 {
fmt.Println(res.Value)
return nil
}
if _, ok := res.Value.(Scalar); ok {
err = cmd.compareResult(Scalar{V: vec[0].Point.V})
} else {
err = cmd.compareResult(vec)
}
if err != nil {
return fmt.Errorf("error in %s %s rande mode: %s", cmd, cmd.expr, err)
}
default: return ts.Test.exec(tc)
}
storage := testutil.NewStorage(t)
return &storage
return nil
}

func NewTestShell() *TestShell {
ts := &TestShell{
Test: Test{
T: t{},
cmds: []TestCommand{},
}}
ts.Test.exec(&clearCmd{})
return ts
}
6 changes: 2 additions & 4 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ import (
"github.com/c-bata/go-prompt"
"github.com/kevinjqiu/promcli/pkg"
"fmt"
"github.com/prometheus/prometheus/promql"
)
)

const Banner = `
____ ____ _ ___
Expand All @@ -16,8 +15,7 @@ const Banner = `


func executor(input string) {
storage := promql.NewTestStorage()
pkg.Executor(input, storage)
pkg.Executor(input)
}

func main() {
Expand Down
57 changes: 28 additions & 29 deletions pkg/executor.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package pkg

import (
"github.com/prometheus/prometheus/storage"
"strings"
"strings"
"fmt"
"github.com/prometheus/prometheus/promql"
)
Expand All @@ -18,73 +17,73 @@ var ApplicationState struct {
buffer []string
}

func Init() {
var testShell *promql.TestShell

func init() {
ApplicationState.state = StateCommand
ApplicationState.buffer = make([]string, 0)
testShell = promql.NewTestShell()
}

func execute(input string, storage *storage.Storage) *storage.Storage {
func execute(input string) {
cmds, err := promql.ParseTestCommand(input)
if err != nil {
fmt.Println(err.Error())
}
for _, cmd := range cmds {
storage, err = promql.ExecuteTestCommand(cmd, storage)
if err != nil {
fmt.Println(err.Error())
}

testShell.SetCmds(cmds)
err = testShell.Run()
if err != nil {
fmt.Println(err.Error())
}
return storage
}

func handleClear(input string, storage *storage.Storage) *storage.Storage {
return execute(input, storage)
func handleClear(input string) {
execute(input)
}

func handleLoad(input string, storage *storage.Storage) *storage.Storage {
func handleLoad(input string) {
if ApplicationState.state == StateLoad {
fmt.Println("Already in Loading state")
return storage
return
}
ApplicationState.state = StateLoad
ApplicationState.buffer = append(ApplicationState.buffer, input)
return storage
return
}

func handleEval(input string, storage *storage.Storage) *storage.Storage {
func handleEval(input string) {
if ApplicationState.state == StateEval {
fmt.Println("Already in Eval state")
return storage
return
}
ApplicationState.state = StateEval
ApplicationState.buffer = append(ApplicationState.buffer, input)
return storage
return
}

func handleEmptyLine(input string, storage *storage.Storage) *storage.Storage {
func handleEmptyLine(input string) {
if ApplicationState.state == StateLoad || ApplicationState.state == StateEval {
lines := strings.Join(ApplicationState.buffer, "\n")
storage = execute(lines, storage)
execute(lines)
ApplicationState.buffer = make([]string, 0)
ApplicationState.state = StateCommand
}
return storage
}

func handleOther(input string, storage *storage.Storage) *storage.Storage {
func handleOther(input string) {
if ApplicationState.state == StateLoad || ApplicationState.state == StateEval {
ApplicationState.buffer = append(ApplicationState.buffer, input)
}
return storage
}

func Executor(input string, storage *storage.Storage) {
func Executor(input string) {
switch {
case input == "clear": storage = handleClear(input, storage)
case strings.HasPrefix(input, "load"): storage = handleLoad(input, storage)
case strings.HasPrefix(input, "eval"): storage = handleEval(input, storage) // TODO: promql.test's eval evaluates against expectations. We need it to display the result of an evaluation.
case input == "": storage = handleEmptyLine(input, storage)
default: storage = handleOther(input, storage)
case input == "clear": handleClear(input)
case strings.HasPrefix(input, "load"): handleLoad(input)
case strings.HasPrefix(input, "eval"): handleEval(input) // TODO: promql.test's eval evaluates against expectations. We need it to display the result of an evaluation.
case input == "": handleEmptyLine(input)
default: handleOther(input)
}
}

0 comments on commit 8e0926f

Please sign in to comment.