TestData: Introduce schema types (#62130)

* schematize data query

* add the stuff you dingus

* feat(testdatasource): add scenario to generated types

* use generated testdata query in frontend

* update code owners

* Add path exception for testdata datasource

* use specific numeric data types

* fix test

* fix e2e smoketest

* add test data query type

* use test data query type

* fix betterer

* Fix typo

* move to experimental

Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com>

Co-authored-by: Jack Westbrook <jack.westbrook@gmail.com>
Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>
Co-authored-by: sam boyer <sdboyer@grafana.com>
Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com>
pull/62241/head
Will Browne 2 years ago committed by GitHub
parent 0cd14091c4
commit 42732539ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 17
      .betterer.results
  2. 4
      .github/CODEOWNERS
  3. 121
      docs/sources/developers/kinds/composable/testdatadataquery/schema-reference.md
  4. 2
      packages/grafana-e2e/src/flows/addDataSource.ts
  5. 46
      pkg/kindsys/report.json
  6. 5
      pkg/plugins/codegen/jenny_plugingotypes.go
  7. 2
      pkg/tests/api/plugins/data/expectedListResp.json
  8. 338
      pkg/tsdb/testdatasource/kinds/dataquery/types_dataquery_gen.go
  9. 3
      public/app/features/scenes/scenes/demo.tsx
  10. 3
      public/app/features/scenes/scenes/gridMultiTimeRange.tsx
  11. 3
      public/app/features/scenes/scenes/gridWithMultipleData.tsx
  12. 4
      public/app/features/scenes/scenes/queries.ts
  13. 14
      public/app/plugins/datasource/testdata/QueryEditor.test.tsx
  14. 76
      public/app/plugins/datasource/testdata/QueryEditor.tsx
  15. 42
      public/app/plugins/datasource/testdata/__mocks__/scenarios.ts
  16. 2
      public/app/plugins/datasource/testdata/components/CSVWaveEditor.tsx
  17. 4
      public/app/plugins/datasource/testdata/components/NodeGraphEditor.tsx
  18. 2
      public/app/plugins/datasource/testdata/components/PredictablePulseEditor.tsx
  19. 4
      public/app/plugins/datasource/testdata/components/RandomWalkEditor.tsx
  20. 2
      public/app/plugins/datasource/testdata/components/SimulationQueryEditor.tsx
  21. 2
      public/app/plugins/datasource/testdata/components/StreamingClientEditor.tsx
  22. 2
      public/app/plugins/datasource/testdata/components/USAQueryEditor.tsx
  23. 6
      public/app/plugins/datasource/testdata/constants.ts
  24. 117
      public/app/plugins/datasource/testdata/dataquery.cue
  25. 137
      public/app/plugins/datasource/testdata/dataquery.gen.ts
  26. 42
      public/app/plugins/datasource/testdata/datasource.ts
  27. 2
      public/app/plugins/datasource/testdata/plugin.json
  28. 16
      public/app/plugins/datasource/testdata/runStreams.ts
  29. 77
      public/app/plugins/datasource/testdata/types.ts
  30. 6
      public/app/plugins/datasource/testdata/variables.ts

@ -6710,12 +6710,9 @@ exports[`better eslint`] = {
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Do not use any type assertions.", "1"],
[0, 0, 0, "Unexpected any. Specify a different type.", "2"],
[0, 0, 0, "Do not use any type assertions.", "3"],
[0, 0, 0, "Unexpected any. Specify a different type.", "4"],
[0, 0, 0, "Unexpected any. Specify a different type.", "5"],
[0, 0, 0, "Unexpected any. Specify a different type.", "6"],
[0, 0, 0, "Do not use any type assertions.", "7"],
[0, 0, 0, "Unexpected any. Specify a different type.", "8"]
[0, 0, 0, "Unexpected any. Specify a different type.", "3"],
[0, 0, 0, "Do not use any type assertions.", "4"],
[0, 0, 0, "Unexpected any. Specify a different type.", "5"]
],
"public/app/plugins/datasource/testdata/components/PredictablePulseEditor.tsx:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"]
@ -6750,10 +6747,7 @@ exports[`better eslint`] = {
"public/app/plugins/datasource/testdata/datasource.ts:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
[0, 0, 0, "Do not use any type assertions.", "2"],
[0, 0, 0, "Unexpected any. Specify a different type.", "3"],
[0, 0, 0, "Unexpected any. Specify a different type.", "4"],
[0, 0, 0, "Unexpected any. Specify a different type.", "5"]
[0, 0, 0, "Unexpected any. Specify a different type.", "2"]
],
"public/app/plugins/datasource/testdata/module.tsx:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
@ -6773,9 +6767,6 @@ exports[`better eslint`] = {
[0, 0, 0, "Do not use any type assertions.", "0"],
[0, 0, 0, "Do not use any type assertions.", "1"]
],
"public/app/plugins/datasource/testdata/types.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
],
"public/app/plugins/datasource/zipkin/QueryField.test.tsx:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],

@ -259,7 +259,6 @@ WORKFLOW.md @torkelo
/pkg/services/querylibrary/ @grafana/multitenancy-squad
/pkg/services/export/ @grafana/multitenancy-squad
/pkg/infra/filestorage/ @grafana/multitenancy-squad
/pkg/tsdb/testdatasource/ @grafana/multitenancy-squad
/pkg/util/converter/ @grafana/multitenancy-squad
# Alerting
@ -281,6 +280,7 @@ WORKFLOW.md @torkelo
/pkg/services/datasources/ @grafana/plugins-platform-backend
/pkg/services/pluginsintegration/ @grafana/plugins-platform-backend
/pkg/plugins/pfs/ @grafana/plugins-platform-backend @grafana/grafana-as-code
/pkg/tsdb/testdatasource/ @grafana/plugins-platform-backend
# Dashboard previews / crawler (behind feature flag)
/pkg/services/thumbs/ @grafana/multitenancy-squad
@ -486,7 +486,7 @@ lerna.json @grafana/frontend-ops
/public/app/plugins/datasource/cloudwatch/ @grafana/aws-plugins
/public/app/plugins/datasource/elasticsearch/ @grafana/observability-logs
/public/app/plugins/datasource/grafana/ @grafana/user-essentials
/public/app/plugins/datasource/testdata/ @grafana/backend-platform
/public/app/plugins/datasource/testdata/ @grafana/plugins-platform-frontend
/public/app/plugins/datasource/grafana-azure-monitor-datasource/ @grafana/partner-plugins
/public/app/plugins/datasource/graphite/ @grafana/observability-metrics
/public/app/plugins/datasource/influxdb/ @grafana/observability-metrics

@ -0,0 +1,121 @@
---
keywords:
- grafana
- schema
title: TestDataDataQuery kind
---
> Both documentation generation and kinds schemas are in active development and subject to change without prior notice.
# TestDataDataQuery kind
## Maturity: experimental
## Version: 0.0
## Properties
| Property | Type | Required | Description |
|-------------------|-------------------------------------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `alias` | string | No | |
| `channel` | string | No | |
| `csvContent` | string | No | |
| `csvFileName` | string | No | |
| `csvWave` | [CSVWave](#csvwave)[] | No | |
| `errorType` | string | No | Possible values are: `server_panic`, `frontend_exception`, `frontend_observable`. |
| `labels` | string | No | |
| `levelColumn` | boolean | No | |
| `lines` | integer | No | |
| `nodes` | [NodesQuery](#nodesquery) | No | |
| `points` | array[] | No | |
| `pulseWave` | [PulseWaveQuery](#pulsewavequery) | No | |
| `rawFrameContent` | string | No | |
| `scenarioId` | string | No | Possible values are: `random_walk`, `slow_query`, `random_walk_with_error`, `random_walk_table`, `exponential_heatmap_bucket_data`, `linear_heatmap_bucket_data`, `no_data_points`, `datapoints_outside_range`, `csv_metric_values`, `predictable_pulse`, `predictable_csv_wave`, `streaming_client`, `simulation`, `usa`, `live`, `grafana_api`, `arrow`, `annotations`, `table_static`, `server_error_500`, `logs`, `node_graph`, `flame_graph`, `raw_frame`, `csv_file`, `csv_content`, `trace`, `manual_entry`, `variables-query`. |
| `seriesCount` | integer | No | |
| `sim` | [SimulationQuery](#simulationquery) | No | |
| `spanCount` | integer | No | |
| `stream` | [StreamingQuery](#streamingquery) | No | |
| `stringInput` | string | No | |
| `usa` | [USAQuery](#usaquery) | No | |
## CSVWave
### Properties
| Property | Type | Required | Description |
|-------------|---------|----------|-------------|
| `labels` | string | No | |
| `name` | string | No | |
| `timeStep` | integer | No | |
| `valuesCSV` | string | No | |
## NodesQuery
### Properties
| Property | Type | Required | Description |
|----------|---------|----------|------------------------------------------------------------|
| `count` | integer | No | |
| `type` | string | No | Possible values are: `random`, `response`, `random edges`. |
## PulseWaveQuery
### Properties
| Property | Type | Required | Description |
|------------|---------|----------|-------------|
| `offCount` | integer | No | |
| `offValue` | number | No | |
| `onCount` | integer | No | |
| `onValue` | number | No | |
| `timeStep` | integer | No | |
## SimulationQuery
### Properties
| Property | Type | Required | Description |
|----------|-------------------|----------|-------------|
| `key` | [object](#key) | **Yes** | |
| `config` | [object](#config) | No | |
| `last` | boolean | No | |
| `stream` | boolean | No | |
### config
| Property | Type | Required | Description |
|----------|------|----------|-------------|
### key
#### Properties
| Property | Type | Required | Description |
|----------|--------|----------|-------------|
| `tick` | number | **Yes** | |
| `type` | string | **Yes** | |
| `uid` | string | No | |
## StreamingQuery
### Properties
| Property | Type | Required | Description |
|----------|---------|----------|-------------------------------------------------|
| `noise` | integer | **Yes** | |
| `speed` | integer | **Yes** | |
| `spread` | integer | **Yes** | |
| `type` | string | **Yes** | Possible values are: `signal`, `logs`, `fetch`. |
| `bands` | integer | No | |
| `url` | string | No | |
## USAQuery
### Properties
| Property | Type | Required | Description |
|----------|----------|----------|-------------|
| `fields` | string[] | No | |
| `mode` | string | No | |
| `period` | string | No | |
| `states` | string[] | No | |

@ -26,7 +26,7 @@ export const addDataSource = (config?: Partial<AddDataSourceConfig>) => {
form: () => {},
name: `e2e-${uuidv4()}`,
skipTlsVerify: false,
type: 'TestData DB',
type: 'TestData',
...config,
};

@ -1539,9 +1539,11 @@
"pluralName": "TempoDataSourceCfgs",
"schemaInterface": "DataSourceCfg"
},
"testdatadbdataquery": {
"testdatadataquery": {
"category": "composable",
"codeowners": [],
"codeowners": [
"grafana/plugins-platform-frontend"
],
"currentVersion": [
0,
0
@ -1549,19 +1551,19 @@
"grafanaMaturityCount": 0,
"lineageIsGroup": false,
"links": {
"docs": "n/a",
"go": "n/a",
"schema": "n/a",
"ts": "n/a"
"docs": "https://grafana.com/docs/grafana/next/developers/kinds/composable/testdatadataquery/schema-reference",
"go": "https://github.com/grafana/grafana/tree/main/pkg/tsdb/testdata/kinds/dataquery/types_dataquery_gen.go",
"schema": "https://github.com/grafana/grafana/tree/main/public/app/plugins/datasource/testdata/dataquery.cue",
"ts": "https://github.com/grafana/grafana/tree/main/public/app/plugins/datasource/testdata/dataquery.gen.ts"
},
"machineName": "testdatadbdataquery",
"maturity": "planned",
"name": "TestDataDBDataQuery",
"pluralMachineName": "testdatadbdataquerys",
"pluralName": "TestDataDBDataQuerys",
"machineName": "testdatadataquery",
"maturity": "experimental",
"name": "TestDataDataQuery",
"pluralMachineName": "testdatadataquerys",
"pluralName": "TestDataDataQuerys",
"schemaInterface": "DataQuery"
},
"testdatadbdatasourcecfg": {
"testdatadatasourcecfg": {
"category": "composable",
"codeowners": [],
"currentVersion": [
@ -1576,11 +1578,11 @@
"schema": "n/a",
"ts": "n/a"
},
"machineName": "testdatadbdatasourcecfg",
"machineName": "testdatadatasourcecfg",
"maturity": "planned",
"name": "TestDataDBDataSourceCfg",
"pluralMachineName": "testdatadbdatasourcecfgs",
"pluralName": "TestDataDBDataSourceCfgs",
"name": "TestDataDataSourceCfg",
"pluralMachineName": "testdatadatasourcecfgs",
"pluralName": "TestDataDataSourceCfgs",
"schemaInterface": "DataSourceCfg"
},
"textpanelcfg": {
@ -1824,8 +1826,8 @@
"tableoldpanelcfg",
"tempodataquery",
"tempodatasourcecfg",
"testdatadbdataquery",
"testdatadbdatasourcecfg",
"testdatadataquery",
"testdatadatasourcecfg",
"textpanelcfg",
"tracespanelcfg",
"welcomepanelcfg",
@ -1871,10 +1873,11 @@
"statetimelinepanelcfg",
"statpanelcfg",
"statushistorypanelcfg",
"testdatadataquery",
"textpanelcfg",
"xychartpanelcfg"
],
"count": 14
"count": 15
},
"mature": {
"name": "mature",
@ -1946,8 +1949,7 @@
"tableoldpanelcfg",
"tempodataquery",
"tempodatasourcecfg",
"testdatadbdataquery",
"testdatadbdatasourcecfg",
"testdatadatasourcecfg",
"thumb",
"tracespanelcfg",
"user",
@ -1955,7 +1957,7 @@
"zipkindataquery",
"zipkindatasourcecfg"
],
"count": 58
"count": 57
},
"stable": {
"name": "stable",

@ -51,6 +51,11 @@ func (j *pgoJenny) Generate(decl *pfs.PluginDecl) (*codejen.File, error) {
}
pluginfolder := filepath.Base(decl.PluginPath)
// hardcoded exception for testdata datasource, ONLY because "testdata" is basically a
// language-reserved keyword for Go
if pluginfolder == "testdata" {
pluginfolder = "testdatasource"
}
filename := fmt.Sprintf("types_%s_gen.go", slotname)
return codejen.NewFile(filepath.Join(j.root, pluginfolder, "kinds", slotname, filename), byt, j), nil
}

@ -1437,7 +1437,7 @@
"signatureOrg": ""
},
{
"name": "TestData DB",
"name": "TestData",
"type": "datasource",
"id": "testdata",
"enabled": true,

@ -0,0 +1,338 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
//
// Generated by:
// public/app/plugins/gen.go
// Using jennies:
// PluginGoTypesJenny
//
// Run 'make gen-cue' from repository root to regenerate.
package dataquery
// Defines values for NodesQueryType.
const (
NodesQueryTypeRandom NodesQueryType = "random"
NodesQueryTypeRandomEdges NodesQueryType = "random edges"
NodesQueryTypeResponse NodesQueryType = "response"
)
// Defines values for StreamingQueryType.
const (
StreamingQueryTypeFetch StreamingQueryType = "fetch"
StreamingQueryTypeLogs StreamingQueryType = "logs"
StreamingQueryTypeSignal StreamingQueryType = "signal"
)
// Defines values for ErrorType.
const (
ErrorTypeFrontendException ErrorType = "frontend_exception"
ErrorTypeFrontendObservable ErrorType = "frontend_observable"
ErrorTypeServerPanic ErrorType = "server_panic"
)
// Defines values for NodesType.
const (
NodesTypeRandom NodesType = "random"
NodesTypeRandomEdges NodesType = "random edges"
NodesTypeResponse NodesType = "response"
)
// Defines values for ScenarioId.
const (
ScenarioIdAnnotations ScenarioId = "annotations"
ScenarioIdArrow ScenarioId = "arrow"
ScenarioIdCsvContent ScenarioId = "csv_content"
ScenarioIdCsvFile ScenarioId = "csv_file"
ScenarioIdCsvMetricValues ScenarioId = "csv_metric_values"
ScenarioIdDatapointsOutsideRange ScenarioId = "datapoints_outside_range"
ScenarioIdExponentialHeatmapBucketData ScenarioId = "exponential_heatmap_bucket_data"
ScenarioIdFlameGraph ScenarioId = "flame_graph"
ScenarioIdGrafanaApi ScenarioId = "grafana_api"
ScenarioIdLinearHeatmapBucketData ScenarioId = "linear_heatmap_bucket_data"
ScenarioIdLive ScenarioId = "live"
ScenarioIdLogs ScenarioId = "logs"
ScenarioIdManualEntry ScenarioId = "manual_entry"
ScenarioIdNoDataPoints ScenarioId = "no_data_points"
ScenarioIdNodeGraph ScenarioId = "node_graph"
ScenarioIdPredictableCsvWave ScenarioId = "predictable_csv_wave"
ScenarioIdPredictablePulse ScenarioId = "predictable_pulse"
ScenarioIdRandomWalk ScenarioId = "random_walk"
ScenarioIdRandomWalkTable ScenarioId = "random_walk_table"
ScenarioIdRandomWalkWithError ScenarioId = "random_walk_with_error"
ScenarioIdRawFrame ScenarioId = "raw_frame"
ScenarioIdServerError500 ScenarioId = "server_error_500"
ScenarioIdSimulation ScenarioId = "simulation"
ScenarioIdSlowQuery ScenarioId = "slow_query"
ScenarioIdStreamingClient ScenarioId = "streaming_client"
ScenarioIdTableStatic ScenarioId = "table_static"
ScenarioIdTrace ScenarioId = "trace"
ScenarioIdUsa ScenarioId = "usa"
ScenarioIdVariablesQuery ScenarioId = "variables-query"
)
// Defines values for StreamType.
const (
StreamTypeFetch StreamType = "fetch"
StreamTypeLogs StreamType = "logs"
StreamTypeSignal StreamType = "signal"
)
// Defines values for TestDataQueryType.
const (
TestDataQueryTypeAnnotations TestDataQueryType = "annotations"
TestDataQueryTypeArrow TestDataQueryType = "arrow"
TestDataQueryTypeCsvContent TestDataQueryType = "csv_content"
TestDataQueryTypeCsvFile TestDataQueryType = "csv_file"
TestDataQueryTypeCsvMetricValues TestDataQueryType = "csv_metric_values"
TestDataQueryTypeDatapointsOutsideRange TestDataQueryType = "datapoints_outside_range"
TestDataQueryTypeExponentialHeatmapBucketData TestDataQueryType = "exponential_heatmap_bucket_data"
TestDataQueryTypeFlameGraph TestDataQueryType = "flame_graph"
TestDataQueryTypeGrafanaApi TestDataQueryType = "grafana_api"
TestDataQueryTypeLinearHeatmapBucketData TestDataQueryType = "linear_heatmap_bucket_data"
TestDataQueryTypeLive TestDataQueryType = "live"
TestDataQueryTypeLogs TestDataQueryType = "logs"
TestDataQueryTypeManualEntry TestDataQueryType = "manual_entry"
TestDataQueryTypeNoDataPoints TestDataQueryType = "no_data_points"
TestDataQueryTypeNodeGraph TestDataQueryType = "node_graph"
TestDataQueryTypePredictableCsvWave TestDataQueryType = "predictable_csv_wave"
TestDataQueryTypePredictablePulse TestDataQueryType = "predictable_pulse"
TestDataQueryTypeRandomWalk TestDataQueryType = "random_walk"
TestDataQueryTypeRandomWalkTable TestDataQueryType = "random_walk_table"
TestDataQueryTypeRandomWalkWithError TestDataQueryType = "random_walk_with_error"
TestDataQueryTypeRawFrame TestDataQueryType = "raw_frame"
TestDataQueryTypeServerError500 TestDataQueryType = "server_error_500"
TestDataQueryTypeSimulation TestDataQueryType = "simulation"
TestDataQueryTypeSlowQuery TestDataQueryType = "slow_query"
TestDataQueryTypeStreamingClient TestDataQueryType = "streaming_client"
TestDataQueryTypeTableStatic TestDataQueryType = "table_static"
TestDataQueryTypeTrace TestDataQueryType = "trace"
TestDataQueryTypeUsa TestDataQueryType = "usa"
TestDataQueryTypeVariablesQuery TestDataQueryType = "variables-query"
)
// CSVWave defines model for CSVWave.
type CSVWave struct {
Labels *string `json:"labels,omitempty"`
Name *string `json:"name,omitempty"`
TimeStep *int64 `json:"timeStep,omitempty"`
ValuesCSV *string `json:"valuesCSV,omitempty"`
}
// NodesQuery defines model for NodesQuery.
type NodesQuery struct {
Count *int64 `json:"count,omitempty"`
Type *NodesQueryType `json:"type,omitempty"`
}
// NodesQueryType defines model for NodesQuery.Type.
type NodesQueryType string
// PulseWaveQuery defines model for PulseWaveQuery.
type PulseWaveQuery struct {
OffCount *int64 `json:"offCount,omitempty"`
OffValue *float64 `json:"offValue,omitempty"`
OnCount *int64 `json:"onCount,omitempty"`
OnValue *float64 `json:"onValue,omitempty"`
TimeStep *int64 `json:"timeStep,omitempty"`
}
// TODO: Should this live here given it's not used in the dataquery?
type Scenario struct {
Description *string `json:"description,omitempty"`
HideAliasField *bool `json:"hideAliasField,omitempty"`
Id string `json:"id"`
Name string `json:"name"`
StringInput string `json:"stringInput"`
}
// SimulationQuery defines model for SimulationQuery.
type SimulationQuery struct {
Config map[string]interface{} `json:"config,omitempty"`
Key struct {
Tick float64 `json:"tick"`
Type string `json:"type"`
Uid *string `json:"uid,omitempty"`
} `json:"key"`
Last *bool `json:"last,omitempty"`
Stream *bool `json:"stream,omitempty"`
}
// StreamingQuery defines model for StreamingQuery.
type StreamingQuery struct {
Bands *int32 `json:"bands,omitempty"`
Noise int32 `json:"noise"`
Speed int32 `json:"speed"`
Spread int32 `json:"spread"`
Type StreamingQueryType `json:"type"`
Url *string `json:"url,omitempty"`
}
// StreamingQueryType defines model for StreamingQuery.Type.
type StreamingQueryType string
// TestDataDataQuery defines model for TestDataDataQuery.
type TestDataDataQuery struct {
Alias *string `json:"alias,omitempty"`
Channel *string `json:"channel,omitempty"`
CsvContent *string `json:"csvContent,omitempty"`
CsvFileName *string `json:"csvFileName,omitempty"`
CsvWave *[]struct {
Labels *string `json:"labels,omitempty"`
Name *string `json:"name,omitempty"`
TimeStep *int64 `json:"timeStep,omitempty"`
ValuesCSV *string `json:"valuesCSV,omitempty"`
} `json:"csvWave,omitempty"`
// For mixed data sources the selected datasource is on the query level.
// For non mixed scenarios this is undefined.
// TODO find a better way to do this ^ that's friendly to schema
// TODO this shouldn't be unknown but DataSourceRef | null
Datasource *interface{} `json:"datasource,omitempty"`
ErrorType *ErrorType `json:"errorType,omitempty"`
// true if query is disabled (ie should not be returned to the dashboard)
Hide *bool `json:"hide,omitempty"`
// Unique, guid like, string used in explore mode
Key *string `json:"key,omitempty"`
Labels *string `json:"labels,omitempty"`
LevelColumn *bool `json:"levelColumn,omitempty"`
Lines *int64 `json:"lines,omitempty"`
Nodes *struct {
Count *int64 `json:"count,omitempty"`
Type *NodesType `json:"type,omitempty"`
} `json:"nodes,omitempty"`
Points *[][]interface{} `json:"points,omitempty"`
PulseWave *struct {
OffCount *int64 `json:"offCount,omitempty"`
OffValue *float64 `json:"offValue,omitempty"`
OnCount *int64 `json:"onCount,omitempty"`
OnValue *float64 `json:"onValue,omitempty"`
TimeStep *int64 `json:"timeStep,omitempty"`
} `json:"pulseWave,omitempty"`
// Specify the query flavor
// TODO make this required and give it a default
QueryType *string `json:"queryType,omitempty"`
RawFrameContent *string `json:"rawFrameContent,omitempty"`
// A - Z
RefId string `json:"refId"`
ScenarioId *ScenarioId `json:"scenarioId,omitempty"`
SeriesCount *int32 `json:"seriesCount,omitempty"`
Sim *struct {
Config map[string]interface{} `json:"config,omitempty"`
Key struct {
Tick float64 `json:"tick"`
Type string `json:"type"`
Uid *string `json:"uid,omitempty"`
} `json:"key"`
Last *bool `json:"last,omitempty"`
Stream *bool `json:"stream,omitempty"`
} `json:"sim,omitempty"`
SpanCount *int32 `json:"spanCount,omitempty"`
Stream *struct {
Bands *int32 `json:"bands,omitempty"`
Noise int32 `json:"noise"`
Speed int32 `json:"speed"`
Spread int32 `json:"spread"`
Type StreamType `json:"type"`
Url *string `json:"url,omitempty"`
} `json:"stream,omitempty"`
StringInput *string `json:"stringInput,omitempty"`
Usa *struct {
Fields *[]string `json:"fields,omitempty"`
Mode *string `json:"mode,omitempty"`
Period *string `json:"period,omitempty"`
States *[]string `json:"states,omitempty"`
} `json:"usa,omitempty"`
}
// ErrorType defines model for TestDataDataQuery.ErrorType.
type ErrorType string
// NodesType defines model for TestDataDataQuery.Nodes.Type.
type NodesType string
// ScenarioId defines model for TestDataDataQuery.ScenarioId.
type ScenarioId string
// StreamType defines model for TestDataDataQuery.Stream.Type.
type StreamType string
// TestDataQueryType defines model for TestDataQueryType.
type TestDataQueryType string
// USAQuery defines model for USAQuery.
type USAQuery struct {
Fields *[]string `json:"fields,omitempty"`
Mode *string `json:"mode,omitempty"`
Period *string `json:"period,omitempty"`
States *[]string `json:"states,omitempty"`
}

@ -8,6 +8,7 @@ import {
SceneToolbarInput,
SceneDataNode,
} from '@grafana/scenes';
import { TestDataQueryType } from 'app/plugins/datasource/testdata/dataquery.gen';
import { panelBuilders } from '../builders/panelBuilders';
import { DashboardScene } from '../dashboard/DashboardScene';
@ -69,7 +70,7 @@ export function getScenePanelRepeaterTest(): DashboardScene {
const queryRunner = getQueryRunnerWithRandomWalkQuery({
seriesCount: 2,
alias: '__server_names',
scenarioId: 'random_walk',
scenarioId: TestDataQueryType.RandomWalk,
});
return new DashboardScene({

@ -1,4 +1,5 @@
import { VizPanel, SceneGridRow, SceneTimePicker, SceneGridLayout, SceneTimeRange } from '@grafana/scenes';
import { TestDataQueryType } from 'app/plugins/datasource/testdata/dataquery.gen';
import { DashboardScene } from '../dashboard/DashboardScene';
import { SceneEditManager } from '../editor/SceneEditManager';
@ -18,7 +19,7 @@ export function getGridWithMultipleTimeRanges(): DashboardScene {
children: [
new SceneGridRow({
$timeRange: row1TimeRange,
$data: getQueryRunnerWithRandomWalkQuery({ scenarioId: 'random_walk_table' }),
$data: getQueryRunnerWithRandomWalkQuery({ scenarioId: TestDataQueryType.RandomWalkTable }),
title: 'Row A - has its own query, last year time range',
key: 'Row A',
isCollapsed: true,

@ -1,4 +1,5 @@
import { VizPanel, SceneGridRow, SceneTimePicker, SceneGridLayout, SceneTimeRange } from '@grafana/scenes';
import { TestDataQueryType } from 'app/plugins/datasource/testdata/dataquery.gen';
import { DashboardScene } from '../dashboard/DashboardScene';
import { SceneEditManager } from '../editor/SceneEditManager';
@ -12,7 +13,7 @@ export function getGridWithMultipleData(): DashboardScene {
children: [
new SceneGridRow({
$timeRange: new SceneTimeRange(),
$data: getQueryRunnerWithRandomWalkQuery({ scenarioId: 'random_walk_table' }),
$data: getQueryRunnerWithRandomWalkQuery({ scenarioId: TestDataQueryType.RandomWalkTable }),
title: 'Row A - has its own query',
key: 'Row A',
isCollapsed: true,

@ -1,8 +1,8 @@
import { QueryRunnerState, SceneQueryRunner } from '@grafana/scenes';
import { TestDataQuery } from 'app/plugins/datasource/testdata/types';
import { TestData } from 'app/plugins/datasource/testdata/dataquery.gen';
export function getQueryRunnerWithRandomWalkQuery(
overrides?: Partial<TestDataQuery>,
overrides?: Partial<TestData>,
queryRunnerOverrides?: Partial<QueryRunnerState>
) {
return new SceneQueryRunner({

@ -5,6 +5,7 @@ import React from 'react';
import { QueryEditor, Props } from './QueryEditor';
import { scenarios } from './__mocks__/scenarios';
import { defaultQuery } from './constants';
import { TestDataQueryType } from './dataquery.gen';
import { defaultStreamQuery } from './runStreams';
beforeEach(() => {
@ -45,11 +46,13 @@ describe('Test Datasource Query Editor', () => {
expect(scs).toHaveLength(scenarios.length);
await userEvent.click(screen.getByText('CSV Metric Values'));
expect(mockOnChange).toHaveBeenCalledWith(expect.objectContaining({ scenarioId: 'csv_metric_values' }));
expect(mockOnChange).toHaveBeenCalledWith(
expect.objectContaining({ scenarioId: TestDataQueryType.CSVMetricValues })
);
await rerender(
<QueryEditor
{...props}
query={{ ...defaultQuery, scenarioId: 'csv_metric_values', stringInput: '1,20,90,30,5,0' }}
query={{ ...defaultQuery, scenarioId: TestDataQueryType.CSVMetricValues, stringInput: '1,20,90,30,5,0' }}
/>
);
expect(await screen.findByRole('textbox', { name: /string input/i })).toBeInTheDocument();
@ -61,7 +64,10 @@ describe('Test Datasource Query Editor', () => {
expect.objectContaining({ scenarioId: 'grafana_api', stringInput: 'datasources' })
);
rerender(
<QueryEditor {...props} query={{ ...defaultQuery, scenarioId: 'grafana_api', stringInput: 'datasources' }} />
<QueryEditor
{...props}
query={{ ...defaultQuery, scenarioId: TestDataQueryType.GrafanaAPI, stringInput: 'datasources' }}
/>
);
expect(await screen.findByText('Grafana API')).toBeInTheDocument();
expect(screen.getByText('Data Sources')).toBeInTheDocument();
@ -72,7 +78,7 @@ describe('Test Datasource Query Editor', () => {
expect.objectContaining({ scenarioId: 'streaming_client', stream: defaultStreamQuery })
);
const streamQuery = { ...defaultQuery, stream: defaultStreamQuery, scenarioId: 'streaming_client' };
const streamQuery = { ...defaultQuery, stream: defaultStreamQuery, scenarioId: TestDataQueryType.StreamingClient };
rerender(<QueryEditor {...props} query={streamQuery} />);

@ -17,9 +17,9 @@ import { RawFrameEditor } from './components/RawFrameEditor';
import { SimulationQueryEditor } from './components/SimulationQueryEditor';
import { USAQueryEditor, usaQueryModes } from './components/USAQueryEditor';
import { defaultCSVWaveQuery, defaultPulseQuery, defaultQuery } from './constants';
import { CSVWave, NodesQuery, TestData, TestDataQueryType, USAQuery } from './dataquery.gen';
import { TestDataDataSource } from './datasource';
import { defaultStreamQuery } from './runStreams';
import { CSVWave, NodesQuery, TestDataQuery, USAQuery } from './types';
const showLabelsFor = ['random_walk', 'predictable_pulse'];
const endpoints = [
@ -32,26 +32,26 @@ const selectors = editorSelectors.components.DataSource.TestData.QueryTab;
export interface EditorProps {
onChange: (value: any) => void;
query: TestDataQuery;
query: TestData;
ds: TestDataDataSource;
}
export type Props = QueryEditorProps<TestDataDataSource, TestDataQuery>;
export type Props = QueryEditorProps<TestDataDataSource, TestData>;
export const QueryEditor = ({ query, datasource, onChange, onRunQuery }: Props) => {
query = { ...defaultQuery, ...query };
const { loading, value: scenarioList } = useAsync(async () => {
// migrate manual_entry (unusable since 7, removed in 8)
if (query.scenarioId === 'manual_entry' && (query as any).points) {
if (query.scenarioId === TestDataQueryType.ManualEntry && query.points) {
let csvContent = 'Time,Value\n';
for (const point of (query as any).points) {
for (const point of query.points) {
csvContent += `${point[1]},${point[0]}\n`;
}
onChange({
refId: query.refId,
datasource: query.datasource,
scenarioId: 'csv_content',
scenarioId: TestDataQueryType.CSVContent,
csvContent,
});
}
@ -64,7 +64,7 @@ export const QueryEditor = ({ query, datasource, onChange, onRunQuery }: Props)
}));
}, []);
const onUpdate = (query: TestDataQuery) => {
const onUpdate = (query: TestData) => {
onChange(query);
onRunQuery();
};
@ -84,8 +84,8 @@ export const QueryEditor = ({ query, datasource, onChange, onRunQuery }: Props)
}
// Clear model from existing props that belong to other scenarios
const update: TestDataQuery = {
scenarioId: item.value!,
const update: TestData = {
scenarioId: item.value! as TestDataQueryType,
refId: query.refId,
alias: query.alias,
datasource: query.datasource,
@ -96,25 +96,25 @@ export const QueryEditor = ({ query, datasource, onChange, onRunQuery }: Props)
}
switch (scenario.id) {
case 'grafana_api':
case TestDataQueryType.GrafanaAPI:
update.stringInput = 'datasources';
break;
case 'streaming_client':
case TestDataQueryType.StreamingClient:
update.stream = defaultStreamQuery;
break;
case 'live':
case TestDataQueryType.Live:
update.channel = 'random-2s-stream'; // default stream
break;
case 'simulation':
case TestDataQueryType.Simulation:
update.sim = { key: { type: 'flight', tick: 10 } }; // default stream
break;
case 'predictable_pulse':
case TestDataQueryType.PredictablePulse:
update.pulseWave = defaultPulseQuery;
break;
case 'predictable_csv_wave':
case TestDataQueryType.PredictableCSVWave:
update.csvWave = defaultCSVWaveQuery;
break;
case 'usa':
case TestDataQueryType.USA:
update.usa = {
mode: usaQueryModes[0].value,
};
@ -243,16 +243,24 @@ export const QueryEditor = ({ query, datasource, onChange, onRunQuery }: Props)
)}
</InlineFieldRow>
{scenarioId === 'random_walk' && <RandomWalkEditor onChange={onInputChange} query={query} ds={datasource} />}
{scenarioId === 'streaming_client' && (
{scenarioId === TestDataQueryType.RandomWalk && (
<RandomWalkEditor onChange={onInputChange} query={query} ds={datasource} />
)}
{scenarioId === TestDataQueryType.StreamingClient && (
<StreamingClientEditor onChange={onStreamClientChange} query={query} ds={datasource} />
)}
{scenarioId === 'live' && <GrafanaLiveEditor onChange={onUpdate} query={query} ds={datasource} />}
{scenarioId === 'simulation' && <SimulationQueryEditor onChange={onUpdate} query={query} ds={datasource} />}
{scenarioId === 'raw_frame' && <RawFrameEditor onChange={onUpdate} query={query} ds={datasource} />}
{scenarioId === 'csv_file' && <CSVFileEditor onChange={onUpdate} query={query} ds={datasource} />}
{scenarioId === 'csv_content' && <CSVContentEditor onChange={onUpdate} query={query} ds={datasource} />}
{scenarioId === 'logs' && (
{scenarioId === TestDataQueryType.Live && <GrafanaLiveEditor onChange={onUpdate} query={query} ds={datasource} />}
{scenarioId === TestDataQueryType.Simulation && (
<SimulationQueryEditor onChange={onUpdate} query={query} ds={datasource} />
)}
{scenarioId === TestDataQueryType.RawFrame && (
<RawFrameEditor onChange={onUpdate} query={query} ds={datasource} />
)}
{scenarioId === TestDataQueryType.CSVFile && <CSVFileEditor onChange={onUpdate} query={query} ds={datasource} />}
{scenarioId === TestDataQueryType.CSVContent && (
<CSVContentEditor onChange={onUpdate} query={query} ds={datasource} />
)}
{scenarioId === TestDataQueryType.Logs && (
<InlineFieldRow>
<InlineField label="Lines" labelWidth={14}>
<Input
@ -270,8 +278,8 @@ export const QueryEditor = ({ query, datasource, onChange, onRunQuery }: Props)
</InlineFieldRow>
)}
{scenarioId === 'usa' && <USAQueryEditor onChange={onUSAStatsChange} query={query.usa ?? {}} />}
{scenarioId === 'grafana_api' && (
{scenarioId === TestDataQueryType.USA && <USAQueryEditor onChange={onUSAStatsChange} query={query.usa ?? {}} />}
{scenarioId === TestDataQueryType.GrafanaAPI && (
<InlineField labelWidth={14} label="Endpoint">
<Select
options={endpoints}
@ -282,7 +290,7 @@ export const QueryEditor = ({ query, datasource, onChange, onRunQuery }: Props)
</InlineField>
)}
{scenarioId === 'arrow' && (
{scenarioId === TestDataQueryType.Arrow && (
<InlineField grow>
<TextArea
name="stringInput"
@ -294,15 +302,19 @@ export const QueryEditor = ({ query, datasource, onChange, onRunQuery }: Props)
</InlineField>
)}
{scenarioId === 'predictable_pulse' && (
{scenarioId === TestDataQueryType.PredictablePulse && (
<PredictablePulseEditor onChange={onPulseWaveChange} query={query} ds={datasource} />
)}
{scenarioId === 'predictable_csv_wave' && <CSVWavesEditor onChange={onCSVWaveChange} waves={query.csvWave} />}
{scenarioId === 'node_graph' && (
{scenarioId === TestDataQueryType.PredictableCSVWave && (
<CSVWavesEditor onChange={onCSVWaveChange} waves={query.csvWave} />
)}
{scenarioId === TestDataQueryType.NodeGraph && (
<NodeGraphEditor onChange={(val: NodesQuery) => onChange({ ...query, nodes: val })} query={query} />
)}
{scenarioId === 'server_error_500' && <ErrorEditor onChange={onUpdate} query={query} ds={datasource} />}
{scenarioId === 'trace' && (
{scenarioId === TestDataQueryType.ServerError500 && (
<ErrorEditor onChange={onUpdate} query={query} ds={datasource} />
)}
{scenarioId === TestDataQueryType.Trace && (
<InlineField labelWidth={14} label="Span count">
<Input
type="number"

@ -1,122 +1,124 @@
import { TestDataQueryType } from '../dataquery.gen';
export const scenarios = [
{
description: '',
id: 'annotations',
id: TestDataQueryType.Annotations,
name: 'Annotations',
stringInput: '',
},
{
description: '',
id: 'arrow',
id: TestDataQueryType.Arrow,
name: 'Load Apache Arrow Data',
stringInput: '',
},
{
description: '',
id: 'csv_metric_values',
id: TestDataQueryType.CSVMetricValues,
name: 'CSV Metric Values',
stringInput: '1,20,90,30,5,0',
},
{
description: '',
id: 'datapoints_outside_range',
id: TestDataQueryType.DataPointsOutsideRange,
name: 'Datapoints Outside Range',
stringInput: '',
},
{
description: '',
id: 'exponential_heatmap_bucket_data',
id: TestDataQueryType.ExponentialHeatmapBucketData,
name: 'Exponential heatmap bucket data',
stringInput: '',
},
{
description: '',
id: 'grafana_api',
id: TestDataQueryType.GrafanaAPI,
name: 'Grafana API',
stringInput: '',
},
{
description: '',
id: 'linear_heatmap_bucket_data',
id: TestDataQueryType.LinearHeatmapBucketData,
name: 'Linear heatmap bucket data',
stringInput: '',
},
{
description: '',
id: 'logs',
id: TestDataQueryType.Logs,
name: 'Logs',
stringInput: '',
},
{
description: '',
id: 'manual_entry',
id: TestDataQueryType.ManualEntry,
name: 'Manual Entry',
stringInput: '',
},
{
description: '',
id: 'no_data_points',
id: TestDataQueryType.NoDataPoints,
name: 'No Data Points',
stringInput: '',
},
{
description: '',
id: 'predictable_csv_wave',
id: TestDataQueryType.PredictableCSVWave,
name: 'Predictable CSV Wave',
stringInput: '',
},
{
description:
'Predictable Pulse returns a pulse wave where there is a datapoint every timeStepSeconds.\nThe wave cycles at timeStepSeconds*(onCount+offCount).\nThe cycle of the wave is based off of absolute time (from the epoch) which makes it predictable.\nTimestamps will line up evenly on timeStepSeconds (For example, 60 seconds means times will all end in :00 seconds).',
id: 'predictable_pulse',
id: TestDataQueryType.PredictablePulse,
name: 'Predictable Pulse',
stringInput: '',
},
{
description: '',
id: 'random_walk',
id: TestDataQueryType.RandomWalk,
name: 'Random Walk',
stringInput: '',
},
{
description: '',
id: 'random_walk_table',
id: TestDataQueryType.RandomWalkTable,
name: 'Random Walk Table',
stringInput: '',
},
{
description: '',
id: 'random_walk_with_error',
id: TestDataQueryType.RandomWalkWithError,
name: 'Random Walk (with error)',
stringInput: '',
},
{
description: '',
id: 'server_error_500',
id: TestDataQueryType.ServerError500,
name: 'Server Error (500)',
stringInput: '',
},
{
description: '',
id: 'slow_query',
id: TestDataQueryType.SlowQuery,
name: 'Slow Query',
stringInput: '5s',
},
{
description: '',
id: 'streaming_client',
id: TestDataQueryType.StreamingClient,
name: 'Streaming Client',
stringInput: '',
},
{
description: '',
id: 'table_static',
id: TestDataQueryType.TableStatic,
name: 'Table Static',
stringInput: '',
},
{
description: '',
id: 'flame_graph',
id: TestDataQueryType.FlameGraph,
name: 'Flame Graph',
stringInput: '',
},

@ -3,7 +3,7 @@ import React, { PureComponent, useState } from 'react';
import { Button, InlineField, InlineFieldRow, Input } from '@grafana/ui';
import { defaultCSVWaveQuery } from '../constants';
import type { CSVWave } from '../types';
import type { CSVWave } from '../dataquery.gen';
interface WavesProps {
waves?: CSVWave[];

@ -2,11 +2,11 @@ import React from 'react';
import { Input, InlineFieldRow, InlineField, Select } from '@grafana/ui';
import { NodesQuery, TestDataQuery } from '../types';
import { NodesQuery, TestData } from '../dataquery.gen';
export interface Props {
onChange: (value: NodesQuery) => void;
query: TestDataQuery;
query: TestData;
}
export function NodeGraphEditor({ query, onChange }: Props) {
const type = query.nodes?.type || 'random';

@ -3,7 +3,7 @@ import React, { ChangeEvent } from 'react';
import { InlineField, InlineFieldRow, Input } from '@grafana/ui';
import { EditorProps } from '../QueryEditor';
import { PulseWaveQuery } from '../types';
import { PulseWaveQuery } from '../dataquery.gen';
const fields = [
{ label: 'Step', id: 'timeStep', placeholder: '60', tooltip: 'The number of seconds between datapoints.' },

@ -4,7 +4,7 @@ import { selectors } from '@grafana/e2e-selectors';
import { InlineField, InlineFieldRow, Input } from '@grafana/ui';
import { EditorProps } from '../QueryEditor';
import { TestDataQuery } from '../types';
import { TestData } from '../dataquery.gen';
const randomWalkFields = [
{ label: 'Series count', id: 'seriesCount', placeholder: '1', min: 1, step: 1 },
@ -41,7 +41,7 @@ export const RandomWalkEditor = ({ onChange, query }: EditorProps) => {
id={`randomWalk-${id}-${query.refId}`}
min={min}
step={step}
value={(query as any)[id as keyof TestDataQuery] || placeholder}
value={(query as any)[id as keyof TestData] || placeholder}
placeholder={placeholder}
onChange={onChange}
/>

@ -5,7 +5,7 @@ import { DataFrameJSON, SelectableValue } from '@grafana/data';
import { InlineField, InlineFieldRow, InlineSwitch, Input, Label, Select } from '@grafana/ui';
import { EditorProps } from '../QueryEditor';
import { SimulationQuery } from '../types';
import { SimulationQuery } from '../dataquery.gen';
import { SimulationSchemaForm } from './SimulationSchemaForm';

@ -4,7 +4,7 @@ import { SelectableValue } from '@grafana/data';
import { InlineField, InlineFieldRow, Input, Select } from '@grafana/ui';
import { EditorProps } from '../QueryEditor';
import { StreamingQuery } from '../types';
import { StreamingQuery } from '../dataquery.gen';
const streamingClientFields = [
{ label: 'Speed (ms)', id: 'speed', placeholder: 'value', min: 10, step: 10 },

@ -3,7 +3,7 @@ import React from 'react';
import { SelectableValue } from '@grafana/data';
import { InlineFieldRow, InlineField, Select, MultiSelect, Input } from '@grafana/ui';
import { USAQuery } from '../types';
import { USAQuery } from '../dataquery.gen';
export interface Props {
onChange: (value: USAQuery) => void;

@ -1,4 +1,4 @@
import { CSVWave, TestDataQuery } from './types';
import { CSVWave, TestData, TestDataQueryType } from './dataquery.gen';
export const defaultPulseQuery: any = {
timeStep: 60,
@ -15,7 +15,7 @@ export const defaultCSVWaveQuery: CSVWave[] = [
},
];
export const defaultQuery: TestDataQuery = {
scenarioId: 'random_walk',
export const defaultQuery: TestData = {
scenarioId: TestDataQueryType.RandomWalk,
refId: '',
};

@ -0,0 +1,117 @@
// Copyright 2023 Grafana Labs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package grafanaplugin
import (
"github.com/grafana/grafana/packages/grafana-schema/src/common"
"github.com/grafana/grafana/pkg/plugins/pfs"
)
// This file (with its sibling .cue files) implements pfs.GrafanaPlugin
pfs.GrafanaPlugin
composableKinds: DataQuery: {
maturity: "experimental"
lineage: {
seqs: [
{
schemas: [
{
common.DataQuery
alias?: string
scenarioId?: #TestDataQueryType | *"random_walk"
stringInput?: string
stream?: #StreamingQuery
pulseWave?: #PulseWaveQuery
sim?: #SimulationQuery
csvWave?: [...#CSVWave] //TODO can we prevent partial from being generated
labels?: string
lines?: int64
levelColumn?: bool
channel?: string
nodes?: #NodesQuery
csvFileName?: string
csvContent?: string
rawFrameContent?: string
seriesCount?: int32
usa?: #USAQuery
errorType?: "server_panic" | "frontend_exception" | "frontend_observable"
spanCount?: int32
points?: [...[...string | int64]]
#TestDataQueryType: "random_walk" | "slow_query" | "random_walk_with_error" | "random_walk_table" | "exponential_heatmap_bucket_data" | "linear_heatmap_bucket_data" | "no_data_points" | "datapoints_outside_range" | "csv_metric_values" | "predictable_pulse" | "predictable_csv_wave" | "streaming_client" | "simulation" | "usa" | "live" | "grafana_api" | "arrow" | "annotations" | "table_static" | "server_error_500" | "logs" | "node_graph" | "flame_graph" | "raw_frame" | "csv_file" | "csv_content" | "trace" | "manual_entry" | "variables-query" @cuetsy(kind="enum", memberNames="RandomWalk|SlowQuery|RandomWalkWithError|RandomWalkTable|ExponentialHeatmapBucketData|LinearHeatmapBucketData|NoDataPoints|DataPointsOutsideRange|CSVMetricValues|PredictablePulse|PredictableCSVWave|StreamingClient|Simulation|USA|Live|GrafanaAPI|Arrow|Annotations|TableStatic|ServerError500|Logs|NodeGraph|FlameGraph|RawFrame|CSVFile|CSVContent|Trace|ManualEntry|VariablesQuery")
#StreamingQuery: {
type: "signal" | "logs" | "fetch"
speed: int32
spread: int32
noise: int32
bands?: int32
url?: string
} @cuetsy(kind="interface")
#PulseWaveQuery: {
timeStep?: int64
onCount?: int64
offCount?: int64
onValue?: float64
offValue?: float64
} @cuetsy(kind="interface")
#SimulationQuery: {
key: {
type: string
tick: float64
uid?: string
}
config?: {...}
stream?: bool
last?: bool
} @cuetsy(kind="interface")
#NodesQuery: {
type?: "random" | "response" | "random edges"
count?: int64
} @cuetsy(kind="interface")
#USAQuery: {
mode?: string
period?: string
fields?: [...string]
states?: [...string]
} @cuetsy(kind="interface")
#CSVWave: {
timeStep?: int64
name?: string
valuesCSV?: string
labels?: string
} @cuetsy(kind="interface")
// TODO: Should this live here given it's not used in the dataquery?
#Scenario: {
id: string
name: string
stringInput: string
description?: string
hideAliasField?: bool
} @cuetsy(kind="interface")
},
]
},
]
}
}

@ -0,0 +1,137 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
//
// Generated by:
// public/app/plugins/gen.go
// Using jennies:
// TSTypesJenny
// PluginTSTypesJenny
//
// Run 'make gen-cue' from repository root to regenerate.
import * as common from '@grafana/schema';
export const DataQueryModelVersion = Object.freeze([0, 0]);
export enum TestDataQueryType {
Annotations = 'annotations',
Arrow = 'arrow',
CSVContent = 'csv_content',
CSVFile = 'csv_file',
CSVMetricValues = 'csv_metric_values',
DataPointsOutsideRange = 'datapoints_outside_range',
ExponentialHeatmapBucketData = 'exponential_heatmap_bucket_data',
FlameGraph = 'flame_graph',
GrafanaAPI = 'grafana_api',
LinearHeatmapBucketData = 'linear_heatmap_bucket_data',
Live = 'live',
Logs = 'logs',
ManualEntry = 'manual_entry',
NoDataPoints = 'no_data_points',
NodeGraph = 'node_graph',
PredictableCSVWave = 'predictable_csv_wave',
PredictablePulse = 'predictable_pulse',
RandomWalk = 'random_walk',
RandomWalkTable = 'random_walk_table',
RandomWalkWithError = 'random_walk_with_error',
RawFrame = 'raw_frame',
ServerError500 = 'server_error_500',
Simulation = 'simulation',
SlowQuery = 'slow_query',
StreamingClient = 'streaming_client',
TableStatic = 'table_static',
Trace = 'trace',
USA = 'usa',
VariablesQuery = 'variables-query',
}
export interface StreamingQuery {
bands?: number;
noise: number;
speed: number;
spread: number;
type: ('signal' | 'logs' | 'fetch');
url?: string;
}
export interface PulseWaveQuery {
offCount?: number;
offValue?: number;
onCount?: number;
onValue?: number;
timeStep?: number;
}
export interface SimulationQuery {
config?: Record<string, unknown>;
key: {
type: string;
tick: number;
uid?: string;
};
last?: boolean;
stream?: boolean;
}
export interface NodesQuery {
count?: number;
type?: ('random' | 'response' | 'random edges');
}
export interface USAQuery {
fields?: Array<string>;
mode?: string;
period?: string;
states?: Array<string>;
}
export const defaultUSAQuery: Partial<USAQuery> = {
fields: [],
states: [],
};
export interface CSVWave {
labels?: string;
name?: string;
timeStep?: number;
valuesCSV?: string;
}
/**
* TODO: Should this live here given it's not used in the dataquery?
*/
export interface Scenario {
description?: string;
hideAliasField?: boolean;
id: string;
name: string;
stringInput: string;
}
export interface TestData extends common.DataQuery {
alias?: string;
channel?: string;
csvContent?: string;
csvFileName?: string;
csvWave?: Array<CSVWave>;
errorType?: ('server_panic' | 'frontend_exception' | 'frontend_observable');
labels?: string;
levelColumn?: boolean;
lines?: number;
nodes?: NodesQuery;
points?: Array<Array<(string | number)>>;
pulseWave?: PulseWaveQuery;
rawFrameContent?: string;
scenarioId?: TestDataQueryType;
seriesCount?: number;
sim?: SimulationQuery;
spanCount?: number;
stream?: StreamingQuery;
stringInput?: string;
usa?: USAQuery;
}
export const defaultTestData: Partial<TestData> = {
csvWave: [],
points: [],
scenarioId: TestDataQueryType.RandomWalk,
};

@ -19,14 +19,14 @@ import {
import { DataSourceWithBackend, getBackendSrv, getGrafanaLiveSrv, getTemplateSrv, TemplateSrv } from '@grafana/runtime';
import { getSearchFilterScopedVar } from 'app/features/variables/utils';
import { Scenario, TestData, TestDataQueryType } from './dataquery.gen';
import { queryMetricTree } from './metricTree';
import { generateRandomEdges, generateRandomNodes, savedNodesResponse } from './nodeGraphUtils';
import { runStream } from './runStreams';
import { flameGraphData } from './testData/flameGraphResponse';
import { Scenario, TestDataQuery } from './types';
import { TestDataVariableSupport } from './variables';
export class TestDataDataSource extends DataSourceWithBackend<TestDataQuery> {
export class TestDataDataSource extends DataSourceWithBackend<TestData> {
scenariosCache?: Promise<Scenario[]>;
constructor(
@ -37,8 +37,8 @@ export class TestDataDataSource extends DataSourceWithBackend<TestDataQuery> {
this.variables = new TestDataVariableSupport();
}
query(options: DataQueryRequest<TestDataQuery>): Observable<DataQueryResponse> {
const backendQueries: TestDataQuery[] = [];
query(options: DataQueryRequest<TestData>): Observable<DataQueryResponse> {
const backendQueries: TestData[] = [];
const streams: Array<Observable<DataQueryResponse>> = [];
// Start streams and prepare queries
@ -86,12 +86,12 @@ export class TestDataDataSource extends DataSourceWithBackend<TestDataQuery> {
// Unusable since 7, removed in 8
case 'manual_entry': {
let csvContent = 'Time,Value\n';
if ((target as any).points) {
for (const point of (target as any).points) {
if (target.points) {
for (const point of target.points) {
csvContent += `${point[1]},${point[0]}\n`;
}
}
target.scenarioId = 'csv_content';
target.scenarioId = TestDataQueryType.CSVContent;
target.csvContent = csvContent;
}
@ -115,7 +115,7 @@ export class TestDataDataSource extends DataSourceWithBackend<TestDataQuery> {
return merge(...streams);
}
resolveTemplateVariables(query: TestDataQuery, scopedVars: ScopedVars) {
resolveTemplateVariables(query: TestData, scopedVars: ScopedVars) {
if (query.labels) {
query.labels = this.templateSrv.replace(query.labels, scopedVars);
}
@ -123,7 +123,7 @@ export class TestDataDataSource extends DataSourceWithBackend<TestDataQuery> {
query.alias = this.templateSrv.replace(query.alias, scopedVars);
}
if (query.scenarioId) {
query.scenarioId = this.templateSrv.replace(query.scenarioId, scopedVars);
query.scenarioId = this.templateSrv.replace(query.scenarioId, scopedVars) as TestDataQueryType;
}
if (query.stringInput) {
query.stringInput = this.templateSrv.replace(query.stringInput, scopedVars);
@ -136,7 +136,7 @@ export class TestDataDataSource extends DataSourceWithBackend<TestDataQuery> {
}
}
annotationDataTopicTest(target: TestDataQuery, req: DataQueryRequest<TestDataQuery>): Observable<DataQueryResponse> {
annotationDataTopicTest(target: TestData, req: DataQueryRequest<TestData>): Observable<DataQueryResponse> {
const events = this.buildFakeAnnotationEvents(req.range, 50);
const dataFrame = new ArrayDataFrame(events);
dataFrame.meta = { dataTopic: DataTopic.Annotations };
@ -166,7 +166,7 @@ export class TestDataDataSource extends DataSourceWithBackend<TestDataQuery> {
return Promise.resolve(this.buildFakeAnnotationEvents(options.range, 10));
}
getQueryDisplayText(query: TestDataQuery) {
getQueryDisplayText(query: TestData) {
const scenario = query.scenarioId ?? 'Default scenario';
if (query.alias) {
@ -191,7 +191,7 @@ export class TestDataDataSource extends DataSourceWithBackend<TestDataQuery> {
return this.scenariosCache;
}
variablesQuery(target: TestDataQuery, options: DataQueryRequest<TestDataQuery>): Observable<DataQueryResponse> {
variablesQuery(target: TestData, options: DataQueryRequest<TestData>): Observable<DataQueryResponse> {
const query = target.stringInput ?? '';
const interpolatedQuery = this.templateSrv.replace(
query,
@ -204,7 +204,7 @@ export class TestDataDataSource extends DataSourceWithBackend<TestDataQuery> {
return of({ data: [dataFrame] }).pipe(delay(100));
}
nodesQuery(target: TestDataQuery, options: DataQueryRequest<TestDataQuery>): Observable<DataQueryResponse> {
nodesQuery(target: TestData, options: DataQueryRequest<TestData>): Observable<DataQueryResponse> {
const type = target.nodes?.type || 'random';
let frames: DataFrame[];
switch (type) {
@ -228,7 +228,7 @@ export class TestDataDataSource extends DataSourceWithBackend<TestDataQuery> {
return of({ data: [flameGraphData] }).pipe(delay(100));
}
trace(target: TestDataQuery, options: DataQueryRequest<TestDataQuery>): Observable<DataQueryResponse> {
trace(target: TestData, options: DataQueryRequest<TestData>): Observable<DataQueryResponse> {
const frame = new MutableDataFrame({
meta: {
preferredVisualisationType: 'trace',
@ -266,7 +266,7 @@ export class TestDataDataSource extends DataSourceWithBackend<TestDataQuery> {
return of({ data: [frame] }).pipe(delay(100));
}
rawFrameQuery(target: TestDataQuery, options: DataQueryRequest<TestDataQuery>): Observable<DataQueryResponse> {
rawFrameQuery(target: TestData, options: DataQueryRequest<TestData>): Observable<DataQueryResponse> {
try {
const data = JSON.parse(target.rawFrameContent ?? '[]').map((v: any) => {
const f = toDataFrame(v);
@ -282,10 +282,7 @@ export class TestDataDataSource extends DataSourceWithBackend<TestDataQuery> {
}
}
serverErrorQuery(
target: TestDataQuery,
options: DataQueryRequest<TestDataQuery>
): Observable<DataQueryResponse> | null {
serverErrorQuery(target: TestData, options: DataQueryRequest<TestData>): Observable<DataQueryResponse> | null {
const { errorType } = target;
if (errorType === 'server_panic') {
@ -305,7 +302,7 @@ export class TestDataDataSource extends DataSourceWithBackend<TestDataQuery> {
}
}
function runGrafanaAPI(target: TestDataQuery, req: DataQueryRequest<TestDataQuery>): Observable<DataQueryResponse> {
function runGrafanaAPI(target: TestData, req: DataQueryRequest<TestData>): Observable<DataQueryResponse> {
const url = `/api/${target.stringInput}`;
return from(
getBackendSrv()
@ -322,10 +319,7 @@ function runGrafanaAPI(target: TestDataQuery, req: DataQueryRequest<TestDataQuer
let liveQueryCounter = 1000;
function runGrafanaLiveQuery(
target: TestDataQuery,
req: DataQueryRequest<TestDataQuery>
): Observable<DataQueryResponse> {
function runGrafanaLiveQuery(target: TestData, req: DataQueryRequest<TestData>): Observable<DataQueryResponse> {
if (!target.channel) {
throw new Error(`Missing channel config`);
}

@ -1,6 +1,6 @@
{
"type": "datasource",
"name": "TestData DB",
"name": "TestData",
"id": "testdata",
"metrics": true,

@ -16,7 +16,7 @@ import { liveTimer } from 'app/features/dashboard/dashgrid/liveTimer';
import { StreamingDataFrame } from 'app/features/live/data/StreamingDataFrame';
import { getRandomLine } from './LogIpsum';
import { TestDataQuery, StreamingQuery } from './types';
import { TestData, StreamingQuery } from './dataquery.gen';
export const defaultStreamQuery: StreamingQuery = {
type: 'signal',
@ -26,7 +26,7 @@ export const defaultStreamQuery: StreamingQuery = {
bands: 1,
};
export function runStream(target: TestDataQuery, req: DataQueryRequest<TestDataQuery>): Observable<DataQueryResponse> {
export function runStream(target: TestData, req: DataQueryRequest<TestData>): Observable<DataQueryResponse> {
const query = defaults(target.stream, defaultStreamQuery);
if ('signal' === query.type) {
return runSignalStream(target, query, req);
@ -41,9 +41,9 @@ export function runStream(target: TestDataQuery, req: DataQueryRequest<TestDataQ
}
export function runSignalStream(
target: TestDataQuery,
target: TestData,
query: StreamingQuery,
req: DataQueryRequest<TestDataQuery>
req: DataQueryRequest<TestData>
): Observable<DataQueryResponse> {
return new Observable<DataQueryResponse>((subscriber) => {
const streamId = `signal-${req.panelId}-${target.refId}`;
@ -128,9 +128,9 @@ export function runSignalStream(
}
export function runLogsStream(
target: TestDataQuery,
target: TestData,
query: StreamingQuery,
req: DataQueryRequest<TestDataQuery>
req: DataQueryRequest<TestData>
): Observable<DataQueryResponse> {
return new Observable<DataQueryResponse>((subscriber) => {
const streamId = `logs-${req.panelId}-${target.refId}`;
@ -173,9 +173,9 @@ export function runLogsStream(
}
export function runFetchStream(
target: TestDataQuery,
target: TestData,
query: StreamingQuery,
req: DataQueryRequest<TestDataQuery>
req: DataQueryRequest<TestData>
): Observable<DataQueryResponse> {
return new Observable<DataQueryResponse>((subscriber) => {
const streamId = `fetch-${req.panelId}-${target.refId}`;

@ -1,77 +0,0 @@
import { DataQuery } from '@grafana/data';
export interface Scenario {
id: string;
name: string;
stringInput: string;
description?: string;
hideAliasField?: boolean;
}
export interface TestDataQuery extends DataQuery {
alias?: string;
scenarioId?: string;
stringInput?: string;
stream?: StreamingQuery;
pulseWave?: PulseWaveQuery;
sim?: SimulationQuery;
csvWave?: CSVWave[];
labels?: string;
lines?: number;
levelColumn?: boolean;
channel?: string; // for grafana live
nodes?: NodesQuery;
csvFileName?: string;
csvContent?: string;
rawFrameContent?: string;
seriesCount?: number;
usa?: USAQuery;
errorType?: 'server_panic' | 'frontend_exception' | 'frontend_observable';
spanCount?: number;
}
export interface NodesQuery {
type?: 'random' | 'response' | 'random edges';
count?: number;
}
export interface StreamingQuery {
type: 'signal' | 'logs' | 'fetch';
speed: number;
spread: number;
noise: number; // wiggle around the signal for min/max
bands?: number; // number of bands around the middle band
url?: string; // the Fetch URL
}
export interface SimulationQuery {
key: {
type: string;
tick: number;
uid?: string;
};
config?: Record<string, any>;
stream?: boolean;
last?: boolean;
}
export interface PulseWaveQuery {
timeStep?: number;
onCount?: number;
offCount?: number;
onValue?: number;
offValue?: number;
}
export interface CSVWave {
timeStep?: number;
name?: string;
valuesCSV?: string;
labels?: string;
}
export interface USAQuery {
mode?: string;
period?: string;
fields?: string[]; // foo, bar, baz
states?: string[];
}

@ -1,14 +1,14 @@
import { StandardVariableQuery, StandardVariableSupport } from '@grafana/data';
import { TestData, TestDataQueryType } from './dataquery.gen';
import { TestDataDataSource } from './datasource';
import { TestDataQuery } from './types';
export class TestDataVariableSupport extends StandardVariableSupport<TestDataDataSource> {
toDataQuery(query: StandardVariableQuery): TestDataQuery {
toDataQuery(query: StandardVariableQuery): TestData {
return {
refId: 'TestDataDataSource-QueryVariable',
stringInput: query.query,
scenarioId: 'variables-query',
scenarioId: TestDataQueryType.VariablesQuery,
csvWave: undefined,
};
}

Loading…
Cancel
Save