func TestQueryExecutor_ShowQueries(t *testing.T) { q, err := influxql.ParseQuery(`SELECT count(value) FROM cpu`) if err != nil { t.Fatal(err) } e := influxql.NewQueryExecutor() e.StatementExecutor = &StatementExecutor{ ExecuteStatementFn: func(stmt influxql.Statement, ctx *influxql.ExecutionContext) error { t.Errorf("unexpected statement: %s", stmt) return errUnexpected }, } q, err = influxql.ParseQuery(`SHOW QUERIES`) if err != nil { t.Fatal(err) } results := e.ExecuteQuery(q, "", 100, nil) result := <-results if len(result.Series) != 1 { t.Errorf("expected %d rows, got %d", 1, len(result.Series)) } if result.Err != nil { t.Errorf("unexpected error: %s", result.Err) } }
func TestQueryExecutor_KillQuery(t *testing.T) { q, err := influxql.ParseQuery(`SELECT count(value) FROM cpu`) if err != nil { t.Fatal(err) } qid := make(chan uint64) e := influxql.NewQueryExecutor() e.StatementExecutor = &StatementExecutor{ ExecuteStatementFn: func(stmt influxql.Statement, ctx *influxql.ExecutionContext) error { qid <- ctx.QueryID select { case <-ctx.InterruptCh: return influxql.ErrQueryInterrupted case <-time.After(100 * time.Millisecond): t.Error("killing the query did not close the channel after 100 milliseconds") return errUnexpected } }, } results := e.ExecuteQuery(q, "mydb", 100, nil) q, err = influxql.ParseQuery(fmt.Sprintf("KILL QUERY %d", <-qid)) if err != nil { t.Fatal(err) } discardOutput(e.ExecuteQuery(q, "mydb", 100, nil)) result := <-results if result.Err != influxql.ErrQueryInterrupted { t.Errorf("unexpected error: %s", result.Err) } }
func TestQueryManager_Close(t *testing.T) { q, err := influxql.ParseQuery(`SELECT count(value) FROM cpu`) if err != nil { t.Fatal(err) } qm := influxql.DefaultQueryManager(0) params := influxql.QueryParams{ Query: q, Database: `mydb`, } _, ch, err := qm.AttachQuery(¶ms) if err != nil { t.Fatal(err) } qm.Close() select { case <-ch: case <-time.After(100 * time.Millisecond): t.Error("closing the query manager did not kill the query after 100 milliseconds") } _, _, err = qm.AttachQuery(¶ms) if err == nil || err != influxql.ErrQueryManagerShutdown { t.Errorf("unexpected error: %s", err) } }
// MustParseQuery parses s into a query. Panic on error. func MustParseQuery(s string) *influxql.Query { q, err := influxql.ParseQuery(s) if err != nil { panic(err) } return q }
func TestQueryExecutor_Abort(t *testing.T) { q, err := influxql.ParseQuery(`SELECT count(value) FROM cpu`) if err != nil { t.Fatal(err) } ch1 := make(chan struct{}) ch2 := make(chan struct{}) e := NewQueryExecutor() e.StatementExecutor = &StatementExecutor{ ExecuteStatementFn: func(stmt influxql.Statement, ctx influxql.ExecutionContext) error { <-ch1 if err := ctx.Send(&influxql.Result{Err: errUnexpected}); err != influxql.ErrQueryAborted { t.Errorf("unexpected error: %v", err) } close(ch2) return nil }, } done := make(chan struct{}) close(done) results := e.ExecuteQuery(q, influxql.ExecutionOptions{AbortCh: done}, nil) close(ch1) <-ch2 discardOutput(results) }
func TestQueryExecutor_Limit_Timeout(t *testing.T) { q, err := influxql.ParseQuery(`SELECT count(value) FROM cpu`) if err != nil { t.Fatal(err) } e := influxql.NewQueryExecutor() e.StatementExecutor = &StatementExecutor{ ExecuteStatementFn: func(stmt influxql.Statement, ctx *influxql.ExecutionContext) error { select { case <-ctx.InterruptCh: return influxql.ErrQueryInterrupted case <-time.After(time.Second): t.Errorf("timeout has not killed the query") return errUnexpected } }, } e.QueryTimeout = time.Nanosecond results := e.ExecuteQuery(q, "mydb", 100, nil) result := <-results if result.Err != influxql.ErrQueryTimeoutReached { t.Errorf("unexpected error: %s", result.Err) } }
func TestStatementExecutor_NormalizeDeleteSeries(t *testing.T) { q, err := influxql.ParseQuery("DELETE FROM cpu") if err != nil { t.Fatalf("unexpected error parsing query: %v", err) } stmt := q.Statements[0].(*influxql.DeleteSeriesStatement) s := &coordinator.StatementExecutor{ MetaClient: &internal.MetaClientMock{ DatabaseFn: func(name string) *meta.DatabaseInfo { t.Fatal("meta client should not be called") return nil }, }, } if err := s.NormalizeStatement(stmt, "foo"); err != nil { t.Fatalf("unexpected error normalizing statement: %v", err) } m := stmt.Sources[0].(*influxql.Measurement) if m.Database != "" { t.Fatalf("database rewritten when not supposed to: %v", m.Database) } if m.RetentionPolicy != "" { t.Fatalf("database rewritten when not supposed to: %v", m.RetentionPolicy) } if exp, got := "DELETE FROM cpu", q.String(); exp != got { t.Fatalf("generated query does match parsed: exp %v, got %v", exp, got) } }
func TestQueryExecutor_Interrupt(t *testing.T) { q, err := influxql.ParseQuery(`SELECT count(value) FROM cpu`) if err != nil { t.Fatal(err) } e := influxql.NewQueryExecutor() e.StatementExecutor = &StatementExecutor{ ExecuteStatementFn: func(stmt influxql.Statement, ctx *influxql.ExecutionContext) error { select { case <-ctx.InterruptCh: return influxql.ErrQueryInterrupted case <-time.After(100 * time.Millisecond): t.Error("killing the query did not close the channel after 100 milliseconds") return errUnexpected } }, } closing := make(chan struct{}) results := e.ExecuteQuery(q, "mydb", 100, closing) close(closing) result := <-results if result.Err != influxql.ErrQueryInterrupted { t.Errorf("unexpected error: %s", result.Err) } }
func TestQueryExecutor_Limit_Timeout(t *testing.T) { q, err := influxql.ParseQuery(`SELECT count(value) FROM cpu`) if err != nil { t.Fatal(err) } e := NewQueryExecutor() e.StatementExecutor = &StatementExecutor{ ExecuteStatementFn: func(stmt influxql.Statement, ctx influxql.ExecutionContext) error { select { case <-ctx.InterruptCh: return influxql.ErrQueryInterrupted case <-time.After(time.Second): t.Errorf("timeout has not killed the query") return errUnexpected } }, } e.TaskManager.QueryTimeout = time.Nanosecond results := e.ExecuteQuery(q, influxql.ExecutionOptions{}, nil) result := <-results if result.Err == nil || !strings.Contains(result.Err.Error(), "query-timeout") { t.Errorf("unexpected error: %s", result.Err) } }
func TestQueryManager_Interrupt(t *testing.T) { q, err := influxql.ParseQuery(`SELECT count(value) FROM cpu`) if err != nil { t.Fatal(err) } closing := make(chan struct{}) qm := influxql.DefaultQueryManager(0) params := influxql.QueryParams{ Query: q, Database: `mydb`, InterruptCh: closing, } _, ch, err := qm.AttachQuery(¶ms) if err != nil { t.Fatal(err) } close(closing) select { case <-ch: case <-time.After(100 * time.Millisecond): t.Error("interrupting the query did not close the channel after 100 milliseconds") } }
func TestQueryManager_KillQuery(t *testing.T) { q, err := influxql.ParseQuery(`SELECT count(value) FROM cpu`) if err != nil { t.Fatal(err) } qm := influxql.DefaultQueryManager(0) params := influxql.QueryParams{ Query: q, Database: `mydb`, } qid, ch, err := qm.AttachQuery(¶ms) if err != nil { t.Fatal(err) } qm.KillQuery(qid) select { case <-ch: case <-time.After(100 * time.Millisecond): t.Error("detaching the query did not close the channel after 100 milliseconds") } if err := qm.KillQuery(qid); err == nil || err.Error() != fmt.Sprintf("no such query id: %d", qid) { t.Errorf("incorrect error detaching query, got %s", err) } }
func NewQuery(queryString string) (*Query, error) { query := &Query{} // Parse and validate query q, err := influxql.ParseQuery(queryString) if err != nil { return nil, errors.Wrap(err, "failed to parse InfluxQL query") } if l := len(q.Statements); l != 1 { return nil, fmt.Errorf("query must be a single select statement, got %d statements", l) } var ok bool query.stmt, ok = q.Statements[0].(*influxql.SelectStatement) if !ok { return nil, fmt.Errorf("query is not a select statement %q", q) } // Add in time condition nodes query.startTL = &influxql.TimeLiteral{} startExpr := &influxql.BinaryExpr{ Op: influxql.GTE, LHS: &influxql.VarRef{Val: "time"}, RHS: query.startTL, } query.stopTL = &influxql.TimeLiteral{} stopExpr := &influxql.BinaryExpr{ Op: influxql.LT, LHS: &influxql.VarRef{Val: "time"}, RHS: query.stopTL, } if query.stmt.Condition != nil { query.stmt.Condition = &influxql.BinaryExpr{ Op: influxql.AND, LHS: query.stmt.Condition, RHS: &influxql.BinaryExpr{ Op: influxql.AND, LHS: startExpr, RHS: stopExpr, }, } } else { query.stmt.Condition = &influxql.BinaryExpr{ Op: influxql.AND, LHS: startExpr, RHS: stopExpr, } } return query, nil }
func TestQueryExecutor_InvalidSource(t *testing.T) { e := NewQueryExecutor() e.StatementExecutor = &StatementExecutor{ ExecuteStatementFn: func(stmt influxql.Statement, ctx influxql.ExecutionContext) error { return errors.New("statement executed unexpectedly") }, } for i, tt := range []struct { q string err string }{ { q: `SELECT fieldKey, fieldType FROM _fieldKeys`, err: `unable to use system source '_fieldKeys': use SHOW FIELD KEYS instead`, }, { q: `SELECT "name" FROM _measurements`, err: `unable to use system source '_measurements': use SHOW MEASUREMENTS instead`, }, { q: `SELECT "key" FROM _series`, err: `unable to use system source '_series': use SHOW SERIES instead`, }, { q: `SELECT tagKey FROM _tagKeys`, err: `unable to use system source '_tagKeys': use SHOW TAG KEYS instead`, }, { q: `SELECT "key", value FROM _tags`, err: `unable to use system source '_tags': use SHOW TAG VALUES instead`, }, } { q, err := influxql.ParseQuery(tt.q) if err != nil { t.Errorf("%d. unable to parse: %s", i, tt.q) continue } results := e.ExecuteQuery(q, influxql.ExecutionOptions{}, nil) result := <-results if len(result.Series) != 0 { t.Errorf("%d. expected %d rows, got %d", 0, i, len(result.Series)) } if result.Err == nil || result.Err.Error() != tt.err { t.Errorf("%d. unexpected error: %s", i, result.Err) } } }
func TestQueryExecutor_Close(t *testing.T) { q, err := influxql.ParseQuery(`SELECT count(value) FROM cpu`) if err != nil { t.Fatal(err) } ch1 := make(chan struct{}) ch2 := make(chan struct{}) e := influxql.NewQueryExecutor() e.StatementExecutor = &StatementExecutor{ ExecuteStatementFn: func(stmt influxql.Statement, ctx *influxql.ExecutionContext) error { close(ch1) <-ctx.InterruptCh close(ch2) return influxql.ErrQueryInterrupted }, } results := e.ExecuteQuery(q, "mydb", 100, nil) go func(results <-chan *influxql.Result) { result := <-results if result.Err != influxql.ErrQueryEngineShutdown { t.Errorf("unexpected error: %s", result.Err) } }(results) // Wait for the statement to start executing. <-ch1 // Close the query executor. e.Close() // Check that the statement gets interrupted and finishes. select { case <-ch2: case <-time.After(100 * time.Millisecond): t.Error("closing the query manager did not kill the query after 100 milliseconds") } results = e.ExecuteQuery(q, "mydb", 100, nil) result := <-results if len(result.Series) != 0 { t.Errorf("expected %d rows, got %d", 0, len(result.Series)) } if result.Err != influxql.ErrQueryEngineShutdown { t.Errorf("unexpected error: %s", result.Err) } }
func TestQueryExecutor_AttachQuery(t *testing.T) { q, err := influxql.ParseQuery(`SELECT count(value) FROM cpu`) if err != nil { t.Fatal(err) } e := influxql.NewQueryExecutor() e.StatementExecutor = &StatementExecutor{ ExecuteStatementFn: func(stmt influxql.Statement, ctx *influxql.ExecutionContext) error { if ctx.QueryID != 1 { t.Errorf("incorrect query id: exp=1 got=%d", ctx.QueryID) } return nil }, } discardOutput(e.ExecuteQuery(q, "mydb", 100, nil)) }
func TestQueryExecutor_Panic(t *testing.T) { q, err := influxql.ParseQuery(`SELECT count(value) FROM cpu`) if err != nil { t.Fatal(err) } e := NewQueryExecutor() e.StatementExecutor = &StatementExecutor{ ExecuteStatementFn: func(stmt influxql.Statement, ctx influxql.ExecutionContext) error { panic("test error") }, } results := e.ExecuteQuery(q, influxql.ExecutionOptions{}, nil) result := <-results if len(result.Series) != 0 { t.Errorf("expected %d rows, got %d", 0, len(result.Series)) } if result.Err == nil || result.Err.Error() != "SELECT count(value) FROM cpu [panic:test error]" { t.Errorf("unexpected error: %s", result.Err) } }
func TestQueryManager_AttachQuery(t *testing.T) { q, err := influxql.ParseQuery(`SELECT count(value) FROM cpu`) if err != nil { t.Fatal(err) } qm := influxql.DefaultQueryManager(0) params := influxql.QueryParams{ Query: q, Database: `mydb`, } qid, _, err := qm.AttachQuery(¶ms) if err != nil { t.Fatal(err) } defer qm.KillQuery(qid) if qid != 1 { t.Errorf("incorrect query id: exp=1 got=%d", qid) } }
func TestQueryManager_Queries(t *testing.T) { q, err := influxql.ParseQuery(`SELECT count(value) FROM cpu`) if err != nil { t.Fatal(err) } qm := influxql.DefaultQueryManager(0) params := influxql.QueryParams{ Query: q, Database: `mydb`, } qid, _, err := qm.AttachQuery(¶ms) if err != nil { t.Fatal(err) } queries := qm.Queries() if len(queries) != 1 { t.Errorf("expected 1 query, got %d", len(queries)) } else { qi := queries[0] if qi.ID != qid { t.Errorf("query id: exp=%d got=%d", qid, qi.ID) } if qi.Query != `SELECT count(value) FROM cpu` { t.Errorf("query id: incorrect query string, got '%s'", qi.Query) } if qi.Database != "mydb" { t.Errorf("query id: incorrect database, got %s", qi.Database) } } qm.KillQuery(qid) queries = qm.Queries() if len(queries) != 0 { t.Errorf("expected 0 queries, got %d", len(queries)) } }
func TestQueryExecutor_Limit_ConcurrentQueries(t *testing.T) { q, err := influxql.ParseQuery(`SELECT count(value) FROM cpu`) if err != nil { t.Fatal(err) } qid := make(chan uint64) e := influxql.NewQueryExecutor() e.StatementExecutor = &StatementExecutor{ ExecuteStatementFn: func(stmt influxql.Statement, ctx *influxql.ExecutionContext) error { qid <- ctx.QueryID <-ctx.InterruptCh return influxql.ErrQueryInterrupted }, } e.MaxConcurrentQueries = 1 defer e.Close() // Start first query and wait for it to be executing. go discardOutput(e.ExecuteQuery(q, "mydb", 100, nil)) <-qid // Start second query and expect for it to fail. results := e.ExecuteQuery(q, "mydb", 100, nil) select { case result := <-results: if len(result.Series) != 0 { t.Errorf("expected %d rows, got %d", 0, len(result.Series)) } if result.Err != influxql.ErrMaxConcurrentQueriesReached { t.Errorf("unexpected error: %s", result.Err) } case <-qid: t.Errorf("unexpected statement execution for the second query") } }
func TestQueryManager_Limit_ConcurrentQueries(t *testing.T) { q, err := influxql.ParseQuery(`SELECT count(value) FROM cpu`) if err != nil { t.Fatal(err) } qm := influxql.DefaultQueryManager(1) params := influxql.QueryParams{ Query: q, Database: `mydb`, } qid, _, err := qm.AttachQuery(¶ms) if err != nil { t.Fatal(err) } defer qm.KillQuery(qid) _, _, err = qm.AttachQuery(¶ms) if err == nil || err != influxql.ErrMaxConcurrentQueriesReached { t.Errorf("unexpected error: %s", err) } }
func TestQueryManager_Limit_Timeout(t *testing.T) { q, err := influxql.ParseQuery(`SELECT count(value) FROM cpu`) if err != nil { t.Fatal(err) } qm := influxql.DefaultQueryManager(0) params := influxql.QueryParams{ Query: q, Database: `mydb`, Timeout: time.Nanosecond, } _, ch, err := qm.AttachQuery(¶ms) if err != nil { t.Fatal(err) } select { case <-ch: case <-time.After(time.Millisecond): t.Errorf("timeout has not killed the query") } }