193 lines
4.4 KiB
Go
193 lines
4.4 KiB
Go
package v1validation
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/influxdata/influxdb/v2"
|
|
"github.com/influxdata/influxdb/v2/cmd/influxd/launcher"
|
|
icontext "github.com/influxdata/influxdb/v2/context"
|
|
"github.com/influxdata/influxdb/v2/mock"
|
|
datagen "github.com/influxdata/influxdb/v2/pkg/data/gen"
|
|
"github.com/influxdata/influxdb/v2/storage/reads"
|
|
"github.com/influxdata/influxdb/v2/tests"
|
|
"github.com/influxdata/influxdb/v2/tests/pipeline"
|
|
"github.com/stretchr/testify/assert"
|
|
"go.uber.org/zap/zapcore"
|
|
"gopkg.in/yaml.v2"
|
|
)
|
|
|
|
var skipMap = map[string]string{
|
|
// file_name_without_extension: skip_reason
|
|
}
|
|
|
|
type GeneratedDataset struct {
|
|
Start string `yaml:"start"`
|
|
End string `yaml:"end"`
|
|
Toml string `yaml:"toml"`
|
|
}
|
|
|
|
type TestSuite struct {
|
|
Tests []Test `yaml:"tests"`
|
|
Dataset string `yaml:"dataset"` // Line protocol OR
|
|
Generated *GeneratedDataset `yaml:"generated"` // TOML schema description
|
|
}
|
|
|
|
type Test struct {
|
|
Name string `yaml:"name"`
|
|
Query string `yaml:"query"`
|
|
Result string `yaml:"result"`
|
|
}
|
|
|
|
func TestGoldenFiles(t *testing.T) {
|
|
err := filepath.WalkDir("./goldenfiles", func(path string, info os.DirEntry, err error) error {
|
|
if info.IsDir() {
|
|
return nil
|
|
}
|
|
base := filepath.Base(path)
|
|
ext := filepath.Ext(base)
|
|
testName := strings.TrimSuffix(base, ext)
|
|
t.Run(testName, func(t *testing.T) {
|
|
if reason, ok := skipMap[testName]; ok {
|
|
t.Skip(reason)
|
|
}
|
|
gf := testSuiteFromPath(t, path)
|
|
validate(t, gf)
|
|
})
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
// Unmarshal a TestSuite from a YAML file
|
|
func testSuiteFromPath(t *testing.T, path string) *TestSuite {
|
|
f, err := os.Open(path)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
b, err := io.ReadAll(f)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
gf := &TestSuite{}
|
|
err = yaml.Unmarshal(b, gf)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return gf
|
|
}
|
|
|
|
func validate(t *testing.T, gf *TestSuite) {
|
|
t.Helper()
|
|
ctx := context.Background()
|
|
p := tests.NewDefaultPipeline(t, func(o *launcher.InfluxdOpts) {
|
|
o.LogLevel = zapcore.ErrorLevel
|
|
})
|
|
p.MustOpen()
|
|
defer p.MustClose()
|
|
orgID := p.DefaultOrgID
|
|
bucketID := p.DefaultBucketID
|
|
fx := pipeline.NewBaseFixture(t, p.Pipeline, orgID, bucketID)
|
|
|
|
var dataset string
|
|
|
|
if gf.Generated != nil {
|
|
spec, err := datagen.NewSpecFromToml(gf.Generated.Toml)
|
|
if err != nil {
|
|
t.Fatalf("error processing TOML: %v", err)
|
|
}
|
|
|
|
tryParse := func(s string) (time.Time, error) {
|
|
if v, err := strconv.Atoi(s); err == nil {
|
|
return time.Unix(0, int64(v)), nil
|
|
}
|
|
|
|
return time.Parse(time.RFC3339, s)
|
|
}
|
|
|
|
start, err := tryParse(gf.Generated.Start)
|
|
if err != nil {
|
|
t.Fatalf("error parsing start: %v", err)
|
|
}
|
|
end, err := tryParse(gf.Generated.End)
|
|
if err != nil {
|
|
t.Fatalf("error parsing end: %v", err)
|
|
}
|
|
|
|
if end.Before(start) {
|
|
t.Fatal("error: start must be before end")
|
|
}
|
|
|
|
sg := datagen.NewSeriesGeneratorFromSpec(spec, datagen.TimeRange{
|
|
Start: start,
|
|
End: end,
|
|
})
|
|
|
|
rs := mock.NewResultSetFromSeriesGenerator(sg, mock.WithGeneratorMaxValues(10000))
|
|
var sb strings.Builder
|
|
if err := reads.ResultSetToLineProtocol(&sb, rs); err != nil {
|
|
t.Fatalf("error generating data: %v", err)
|
|
}
|
|
dataset = sb.String()
|
|
if len(dataset) == 0 {
|
|
t.Fatal("no data generated")
|
|
}
|
|
} else {
|
|
dataset = gf.Dataset
|
|
}
|
|
|
|
if err := fx.Admin.WriteBatch(dataset); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
p.Flush()
|
|
|
|
ctx = icontext.SetAuthorizer(ctx, tests.MakeAuthorization(p.DefaultOrgID, p.DefaultUserID, influxdb.OperPermissions()))
|
|
|
|
if err := p.Launcher.DBRPMappingService().Create(ctx, &influxdb.DBRPMapping{
|
|
Database: "mydb",
|
|
RetentionPolicy: "autogen",
|
|
Default: true,
|
|
OrganizationID: orgID,
|
|
BucketID: bucketID,
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
for i := range gf.Tests {
|
|
test := &gf.Tests[i]
|
|
name := test.Name
|
|
if len(name) == 0 {
|
|
name = fmt.Sprintf("query_%02d", i)
|
|
}
|
|
t.Run(name, func(t *testing.T) {
|
|
err := fx.Admin.Client.Get("/query").
|
|
QueryParams([2]string{"db", "mydb"}).
|
|
QueryParams([2]string{"q", test.Query}).
|
|
QueryParams([2]string{"epoch", "ns"}).
|
|
Header("Content-Type", "application/vnd.influxql").
|
|
Header("Accept", "application/csv").
|
|
RespFn(func(resp *http.Response) error {
|
|
b, err := io.ReadAll(resp.Body)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, test.Result, string(b))
|
|
return nil
|
|
}).
|
|
Do(ctx)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
})
|
|
}
|
|
}
|