Commit 2732aca0 by Torkel Ödegaard Committed by GitHub

TestData: Adds important new features to the random walk scenario (#21613)

* test data refactor

* new random walk options

* fixed test

* Added automatic names
parent 79255faf
...@@ -101,7 +101,15 @@ func init() { ...@@ -101,7 +101,15 @@ func init() {
Name: "Random Walk", Name: "Random Walk",
Handler: func(query *tsdb.Query, context *tsdb.TsdbQuery) *tsdb.QueryResult { Handler: func(query *tsdb.Query, context *tsdb.TsdbQuery) *tsdb.QueryResult {
return getRandomWalk(query, context) queryRes := tsdb.NewQueryResult()
seriesCount := query.Model.Get("seriesCount").MustInt(1)
for i := 0; i < seriesCount; i++ {
queryRes.Series = append(queryRes.Series, getRandomWalk(query, context, i))
}
return queryRes
}, },
}) })
...@@ -139,7 +147,10 @@ func init() { ...@@ -139,7 +147,10 @@ func init() {
stringInput := query.Model.Get("stringInput").MustString() stringInput := query.Model.Get("stringInput").MustString()
parsedInterval, _ := time.ParseDuration(stringInput) parsedInterval, _ := time.ParseDuration(stringInput)
time.Sleep(parsedInterval) time.Sleep(parsedInterval)
return getRandomWalk(query, context)
queryRes := tsdb.NewQueryResult()
queryRes.Series = append(queryRes.Series, getRandomWalk(query, context, 0))
return queryRes
}, },
}) })
...@@ -157,7 +168,7 @@ func init() { ...@@ -157,7 +168,7 @@ func init() {
Handler: func(query *tsdb.Query, context *tsdb.TsdbQuery) *tsdb.QueryResult { Handler: func(query *tsdb.Query, context *tsdb.TsdbQuery) *tsdb.QueryResult {
queryRes := tsdb.NewQueryResult() queryRes := tsdb.NewQueryResult()
series := newSeriesForQuery(query) series := newSeriesForQuery(query, 0)
outsideTime := context.TimeRange.MustGetFrom().Add(-1*time.Hour).Unix() * 1000 outsideTime := context.TimeRange.MustGetFrom().Add(-1*time.Hour).Unix() * 1000
series.Points = append(series.Points, tsdb.NewTimePoint(null.FloatFrom(10), float64(outsideTime))) series.Points = append(series.Points, tsdb.NewTimePoint(null.FloatFrom(10), float64(outsideTime)))
...@@ -175,7 +186,7 @@ func init() { ...@@ -175,7 +186,7 @@ func init() {
points := query.Model.Get("points").MustArray() points := query.Model.Get("points").MustArray()
series := newSeriesForQuery(query) series := newSeriesForQuery(query, 0)
startTime := context.TimeRange.GetFromAsMsEpoch() startTime := context.TimeRange.GetFromAsMsEpoch()
endTime := context.TimeRange.GetToAsMsEpoch() endTime := context.TimeRange.GetToAsMsEpoch()
...@@ -230,7 +241,7 @@ func init() { ...@@ -230,7 +241,7 @@ func init() {
return queryRes return queryRes
} }
series := newSeriesForQuery(query) series := newSeriesForQuery(query, 0)
startTime := context.TimeRange.GetFromAsMsEpoch() startTime := context.TimeRange.GetFromAsMsEpoch()
endTime := context.TimeRange.GetToAsMsEpoch() endTime := context.TimeRange.GetToAsMsEpoch()
step := (endTime - startTime) / int64(len(values)-1) step := (endTime - startTime) / int64(len(values)-1)
...@@ -288,7 +299,8 @@ func init() { ...@@ -288,7 +299,8 @@ func init() {
Name: "Random Walk (with error)", Name: "Random Walk (with error)",
Handler: func(query *tsdb.Query, context *tsdb.TsdbQuery) *tsdb.QueryResult { Handler: func(query *tsdb.Query, context *tsdb.TsdbQuery) *tsdb.QueryResult {
queryRes := getRandomWalk(query, context) queryRes := tsdb.NewQueryResult()
queryRes.Series = append(queryRes.Series, getRandomWalk(query, context, 0))
queryRes.ErrorString = "This is an error. It can include URLs http://grafana.com/" queryRes.ErrorString = "This is an error. It can include URLs http://grafana.com/"
return queryRes return queryRes
}, },
...@@ -441,10 +453,11 @@ func getPredictablePulse(query *tsdb.Query, context *tsdb.TsdbQuery) *tsdb.Query ...@@ -441,10 +453,11 @@ func getPredictablePulse(query *tsdb.Query, context *tsdb.TsdbQuery) *tsdb.Query
return queryRes return queryRes
} }
series := newSeriesForQuery(query) series := newSeriesForQuery(query, 0)
series.Points = *points series.Points = *points
series.Tags = parseLabels(query)
queryRes.Series = append(queryRes.Series, series) queryRes.Series = append(queryRes.Series, series)
attachLabels(query, queryRes)
return queryRes return queryRes
} }
...@@ -491,10 +504,11 @@ func getPredictableCSVWave(query *tsdb.Query, context *tsdb.TsdbQuery) *tsdb.Que ...@@ -491,10 +504,11 @@ func getPredictableCSVWave(query *tsdb.Query, context *tsdb.TsdbQuery) *tsdb.Que
return queryRes return queryRes
} }
series := newSeriesForQuery(query) series := newSeriesForQuery(query, 0)
series.Points = *points series.Points = *points
series.Tags = parseLabels(query)
queryRes.Series = append(queryRes.Series, series) queryRes.Series = append(queryRes.Series, series)
attachLabels(query, queryRes)
return queryRes return queryRes
} }
...@@ -520,28 +534,42 @@ func predictableSeries(timeRange *tsdb.TimeRange, timeStep, length int64, getVal ...@@ -520,28 +534,42 @@ func predictableSeries(timeRange *tsdb.TimeRange, timeStep, length int64, getVal
return &points, nil return &points, nil
} }
func getRandomWalk(query *tsdb.Query, tsdbQuery *tsdb.TsdbQuery) *tsdb.QueryResult { func getRandomWalk(query *tsdb.Query, tsdbQuery *tsdb.TsdbQuery, index int) *tsdb.TimeSeries {
timeWalkerMs := tsdbQuery.TimeRange.GetFromAsMsEpoch() timeWalkerMs := tsdbQuery.TimeRange.GetFromAsMsEpoch()
to := tsdbQuery.TimeRange.GetToAsMsEpoch() to := tsdbQuery.TimeRange.GetToAsMsEpoch()
series := newSeriesForQuery(query, index)
series := newSeriesForQuery(query) startValue := query.Model.Get("startValue").MustFloat64(rand.Float64() * 100)
spread := query.Model.Get("spread").MustFloat64(1)
noise := query.Model.Get("noise").MustFloat64(0)
min, hasMin := query.Model.Get("min").Float64()
max, hasMax := query.Model.Get("max").Float64()
points := make(tsdb.TimeSeriesPoints, 0) points := make(tsdb.TimeSeriesPoints, 0)
walker := query.Model.Get("startValue").MustFloat64(rand.Float64() * 100) walker := startValue
for i := int64(0); i < 10000 && timeWalkerMs < to; i++ { for i := int64(0); i < 10000 && timeWalkerMs < to; i++ {
points = append(points, tsdb.NewTimePoint(null.FloatFrom(walker), float64(timeWalkerMs))) nextValue := walker + (rand.Float64() * noise)
if hasMin == nil && nextValue < min {
nextValue = min
walker = min
}
walker += rand.Float64() - 0.5 if hasMax == nil && nextValue > max {
nextValue = max
walker = max
}
points = append(points, tsdb.NewTimePoint(null.FloatFrom(nextValue), float64(timeWalkerMs)))
walker += (rand.Float64() - 0.5) * spread
timeWalkerMs += query.IntervalMs timeWalkerMs += query.IntervalMs
} }
series.Points = points series.Points = points
series.Tags = parseLabels(query)
queryRes := tsdb.NewQueryResult() return series
queryRes.Series = append(queryRes.Series, series)
attachLabels(query, queryRes)
return queryRes
} }
/** /**
...@@ -549,30 +577,19 @@ func getRandomWalk(query *tsdb.Query, tsdbQuery *tsdb.TsdbQuery) *tsdb.QueryResu ...@@ -549,30 +577,19 @@ func getRandomWalk(query *tsdb.Query, tsdbQuery *tsdb.TsdbQuery) *tsdb.QueryResu
* *
* '{job="foo", instance="bar"} => {job: "foo", instance: "bar"}` * '{job="foo", instance="bar"} => {job: "foo", instance: "bar"}`
*/ */
func attachLabels(query *tsdb.Query, queryRes *tsdb.QueryResult) { func parseLabels(query *tsdb.Query) map[string]string {
tags := map[string]string{}
labelText := query.Model.Get("labels").MustString("") labelText := query.Model.Get("labels").MustString("")
if labelText == "" { if labelText == "" {
return return map[string]string{}
}
tags := parseLabels(labelText)
for _, series := range queryRes.Series {
series.Tags = tags
} }
}
// generous parser:
// {job="foo", instance="bar"}
// job="foo", instance="bar"
// job=foo, instance=bar
// should all equal {job=foo, instance=bar}
func parseLabels(text string) map[string]string { text := strings.Trim(labelText, `{}`)
var tags map[string]string
text = strings.Trim(text, `{}`)
if len(text) < 2 { if len(text) < 2 {
return tags return tags
} }
tags = make(map[string]string) tags = make(map[string]string)
for _, keyval := range strings.Split(text, ",") { for _, keyval := range strings.Split(text, ",") {
...@@ -648,10 +665,24 @@ func registerScenario(scenario *Scenario) { ...@@ -648,10 +665,24 @@ func registerScenario(scenario *Scenario) {
ScenarioRegistry[scenario.Id] = scenario ScenarioRegistry[scenario.Id] = scenario
} }
func newSeriesForQuery(query *tsdb.Query) *tsdb.TimeSeries { func newSeriesForQuery(query *tsdb.Query, index int) *tsdb.TimeSeries {
alias := query.Model.Get("alias").MustString("") alias := query.Model.Get("alias").MustString("")
suffix := ""
if index > 0 {
suffix = strconv.Itoa(index)
}
if alias == "" { if alias == "" {
alias = query.RefId + "-series" alias = fmt.Sprintf("%s-series%s", query.RefId, suffix)
}
if alias == "__server_names" && len(serverNames) > index {
alias = serverNames[index]
}
if alias == "__house_locations" && len(houseLocations) > index {
alias = houseLocations[index]
} }
return &tsdb.TimeSeries{Name: alias} return &tsdb.TimeSeries{Name: alias}
...@@ -671,3 +702,49 @@ func fromStringOrNumber(val *simplejson.Json) (null.Float, error) { ...@@ -671,3 +702,49 @@ func fromStringOrNumber(val *simplejson.Json) (null.Float, error) {
return null.Float{}, fmt.Errorf("failed to extract value") return null.Float{}, fmt.Errorf("failed to extract value")
} }
} }
var serverNames = []string{
"Backend-ops-01",
"Backend-ops-02",
"Backend-ops-03",
"Backend-ops-04",
"Frontend-web-01",
"Frontend-web-02",
"Frontend-web-03",
"Frontend-web-04",
"MySQL-01",
"MySQL-02",
"MySQL-03",
"MySQL-04",
"Postgres-01",
"Postgres-02",
"Postgres-03",
"Postgres-04",
"DB-01",
"DB-02",
"SAN-01",
"SAN-02",
"SAN-02",
"SAN-04",
"Kaftka-01",
"Kaftka-02",
"Kaftka-03",
"Zookeeper-01",
"Zookeeper-02",
"Zookeeper-03",
"Zookeeper-04",
}
var houseLocations = []string{
"Cellar",
"Living room",
"Porch",
"Bedroom",
"Guest room",
"Kitchen",
"Playroom",
"Bathroom",
"Outside",
"Roof",
"Terrace",
}
...@@ -99,9 +99,28 @@ func TestToLabels(t *testing.T) { ...@@ -99,9 +99,28 @@ func TestToLabels(t *testing.T) {
tags["job"] = "foo" tags["job"] = "foo"
tags["instance"] = "bar" tags["instance"] = "bar"
So(parseLabels(`{job="foo", instance="bar"}`), ShouldResemble, tags) query1 := tsdb.Query{
So(parseLabels(`job="foo", instance="bar"`), ShouldResemble, tags) Model: simplejson.NewFromAny(map[string]interface{}{
So(parseLabels(`job=foo, instance=bar`), ShouldResemble, tags) "labels": `{job="foo", instance="bar"}`,
So(parseLabels(`job = foo,instance = bar`), ShouldResemble, tags) }),
}
So(parseLabels(&query1), ShouldResemble, tags)
query2 := tsdb.Query{
Model: simplejson.NewFromAny(map[string]interface{}{
"labels": `job=foo, instance=bar`,
}),
}
So(parseLabels(&query2), ShouldResemble, tags)
query3 := tsdb.Query{
Model: simplejson.NewFromAny(map[string]interface{}{
"labels": `job = foo,instance = bar`,
}),
}
So(parseLabels(&query3), ShouldResemble, tags)
}) })
} }
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</div> </div>
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label query-keyword">Alias</label> <label class="gf-form-label query-keyword">Alias</label>
<input type="text" class="gf-form-input max-width-7" placeholder="optional" ng-model="ctrl.target.alias" ng-change="ctrl.refresh()" ng-model-onblur> <input type="text" class="gf-form-input width-14" placeholder="optional" ng-model="ctrl.target.alias" ng-change="ctrl.refresh()" ng-model-onblur>
</div> </div>
<div ng-if="ctrl.showLabels" class="gf-form gf-form--grow"> <div ng-if="ctrl.showLabels" class="gf-form gf-form--grow">
<label class="gf-form-label query-keyword"> <label class="gf-form-label query-keyword">
...@@ -48,6 +48,68 @@ ...@@ -48,6 +48,68 @@
<div class="gf-form-label gf-form-label--grow"></div> <div class="gf-form-label gf-form-label--grow"></div>
</div> </div>
</div> </div>
<div class="gf-form-inline" ng-if="ctrl.scenario.id === 'random_walk'">
<div class="gf-form">
<label class="gf-form-label query-keyword width-7">Series count</label>
<input type="number"
class="gf-form-input width-7"
placeholder="1"
ng-model="ctrl.target.seriesCount"
min="1"
step="1"
ng-change="ctrl.refresh()" />
</div>
<div class="gf-form">
<label class="gf-form-label query-keyword width-7">Start value</label>
<input type="number"
class="gf-form-input width-6"
placeholder="auto"
ng-model="ctrl.target.startValue"
min="1"
step="1"
ng-change="ctrl.refresh()" />
</div>
<div class="gf-form">
<label class="gf-form-label query-keyword width-7">Spread</label>
<input type="number"
class="gf-form-input width-6"
placeholder="1"
ng-model="ctrl.target.spread"
min="0.5"
step="0.1"
ng-change="ctrl.refresh()" />
</div>
<div class="gf-form">
<label class="gf-form-label query-keyword width-7">Noise</label>
<input type="number"
class="gf-form-input width-6"
placeholder="0"
ng-model="ctrl.target.noise"
min="0"
step="0.1"
ng-change="ctrl.refresh()" />
</div>
<div class="gf-form">
<label class="gf-form-label query-keyword width-7">Min</label>
<input type="number"
class="gf-form-input width-6"
placeholder="none"
ng-model="ctrl.target.min"
min="0"
step="0.1"
ng-change="ctrl.refresh()" />
</div>
<div class="gf-form">
<label class="gf-form-label query-keyword width-7">Max</label>
<input type="number"
class="gf-form-input width-6"
placeholder="none"
ng-model="ctrl.target.max"
min="0"
step="0.1"
ng-change="ctrl.refresh()" />
</div>
</div>
<div class="gf-form-inline" ng-if="ctrl.scenario.id === 'streaming_client'"> <div class="gf-form-inline" ng-if="ctrl.scenario.id === 'streaming_client'">
<div class="gf-form gf-form"> <div class="gf-form gf-form">
<label class="gf-form-label query-keyword width-7">Type</label> <label class="gf-form-label query-keyword width-7">Type</label>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment