github.com/influxdata/influxdb/v2@v2.7.6/influxql/v1tests/server_helpers.go (about)

     1  package v1tests
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"io"
     7  	"net/http"
     8  	"net/url"
     9  	"strings"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/influxdata/influxdb/v2"
    14  	"github.com/influxdata/influxdb/v2/cmd/influxd/launcher"
    15  	icontext "github.com/influxdata/influxdb/v2/context"
    16  	"github.com/influxdata/influxdb/v2/kit/platform"
    17  	"github.com/influxdata/influxdb/v2/tests"
    18  	"github.com/influxdata/influxdb/v2/tests/pipeline"
    19  	"github.com/stretchr/testify/assert"
    20  	"github.com/stretchr/testify/require"
    21  	"go.uber.org/zap/zapcore"
    22  )
    23  
    24  func OpenServer(t *testing.T, extra ...launcher.OptSetter) *tests.DefaultPipeline {
    25  	t.Helper()
    26  
    27  	defaults := []launcher.OptSetter{
    28  		func(o *launcher.InfluxdOpts) {
    29  			o.LogLevel = zapcore.ErrorLevel
    30  		},
    31  	}
    32  
    33  	p := tests.NewDefaultPipeline(t, append(defaults, extra...)...)
    34  	p.MustOpen()
    35  	return p
    36  }
    37  
    38  type Query struct {
    39  	name       string
    40  	command    string
    41  	params     url.Values
    42  	exp, got   string
    43  	skip       string
    44  	skipOthers bool // set to true to only run this test
    45  	repeat     int
    46  }
    47  
    48  // Execute runs the command and returns an err if it fails
    49  func (q *Query) Execute(ctx context.Context, t *testing.T, db string, c *tests.Client) (err error) {
    50  	t.Helper()
    51  
    52  	params := [][2]string{{"q", q.command}}
    53  	if qdb := q.params.Get("db"); len(qdb) > 0 {
    54  		params = append(params, [2]string{"db", qdb})
    55  	}
    56  
    57  	if epoch := q.params.Get("epoch"); len(epoch) > 0 {
    58  		params = append(params, [2]string{"epoch", epoch})
    59  	}
    60  
    61  	if parameters := q.params.Get("params"); len(parameters) > 0 {
    62  		params = append(params, [2]string{"params", parameters})
    63  	}
    64  
    65  	if chunked := q.params.Get("chunked"); len(chunked) > 0 {
    66  		params = append(params, [2]string{"chunked", chunked})
    67  	}
    68  
    69  	if chunkSize := q.params.Get("chunk_size"); len(chunkSize) > 0 {
    70  		params = append(params, [2]string{"chunk_size", chunkSize})
    71  	}
    72  
    73  	err = c.Client.Get("/query").
    74  		QueryParams(params...).
    75  		Header("Accept", "application/json").
    76  		RespFn(func(resp *http.Response) error {
    77  			require.Equal(t, "application/json", resp.Header.Get("Content-Type"))
    78  			b, err := io.ReadAll(resp.Body)
    79  			q.got = strings.TrimSpace(string(b))
    80  			return err
    81  		}).
    82  		Do(ctx)
    83  
    84  	return
    85  }
    86  
    87  type Write struct {
    88  	data     string
    89  	bucketID platform.ID
    90  }
    91  
    92  type Writes []*Write
    93  
    94  type Test struct {
    95  	orgID            platform.ID
    96  	bucketID         platform.ID
    97  	db               string
    98  	rp               string
    99  	writes           Writes
   100  	queries          []*Query
   101  	noDefaultMapping bool
   102  	noWrites         bool
   103  }
   104  
   105  func NewTest(db, rp string) Test {
   106  	return Test{
   107  		db: db,
   108  		rp: rp,
   109  	}
   110  }
   111  
   112  // NewEmptyTest creates an empty test without a default database and retention policy mapping or
   113  // any expected writes.
   114  func NewEmptyTest() Test {
   115  	return Test{noDefaultMapping: true, noWrites: true}
   116  }
   117  
   118  func (qt *Test) Run(ctx context.Context, t *testing.T, p *tests.DefaultPipeline) {
   119  	t.Helper()
   120  	fx, auth := qt.init(ctx, t, p)
   121  	ctx = icontext.SetAuthorizer(ctx, auth)
   122  
   123  	skipOthers := false
   124  	for _, query := range qt.queries {
   125  		skipOthers = skipOthers || query.skipOthers
   126  	}
   127  
   128  	var queries []*Query
   129  	if skipOthers {
   130  		queries = make([]*Query, 0, len(qt.queries))
   131  		for _, query := range qt.queries {
   132  			if query.skipOthers {
   133  				queries = append(queries, query)
   134  			}
   135  		}
   136  	} else {
   137  		queries = qt.queries
   138  	}
   139  
   140  	for _, query := range queries {
   141  		t.Run(query.name, func(t *testing.T) {
   142  			if query.skip != "" {
   143  				t.Skipf("SKIP:: %s", query.skip)
   144  			}
   145  			err := query.Execute(ctx, t, qt.db, fx.Admin)
   146  			assert.NoError(t, err)
   147  			assert.Equal(t, query.exp, query.got,
   148  				"%s: unexpected results\nquery:  %s\nparams:  %v\nexp:    %s\nactual: %s\n",
   149  				query.name, query.command, query.params, query.exp, query.got)
   150  		})
   151  	}
   152  }
   153  
   154  func (qt *Test) addQueries(q ...*Query) {
   155  	qt.queries = append(qt.queries, q...)
   156  }
   157  
   158  func (qt *Test) init(ctx context.Context, t *testing.T, p *tests.DefaultPipeline) (fx pipeline.BaseFixture, auth *influxdb.Authorization) {
   159  	t.Helper()
   160  
   161  	qt.orgID = p.DefaultOrgID
   162  	qt.bucketID = p.DefaultBucketID
   163  
   164  	fx = pipeline.NewBaseFixture(t, p.Pipeline, qt.orgID, qt.bucketID)
   165  
   166  	if !qt.noWrites {
   167  		require.Greater(t, len(qt.writes), 0)
   168  		qt.writeTestData(ctx, t, fx.Admin)
   169  		p.Flush()
   170  	}
   171  
   172  	auth = tests.MakeAuthorization(qt.orgID, p.DefaultUserID, influxdb.OperPermissions())
   173  
   174  	if !qt.noDefaultMapping {
   175  		ctx = icontext.SetAuthorizer(ctx, auth)
   176  		err := p.Launcher.
   177  			DBRPMappingService().
   178  			Create(ctx, &influxdb.DBRPMapping{
   179  				Database:        qt.db,
   180  				RetentionPolicy: qt.rp,
   181  				Default:         true,
   182  				OrganizationID:  qt.orgID,
   183  				BucketID:        qt.bucketID,
   184  			})
   185  		require.NoError(t, err)
   186  	}
   187  
   188  	return
   189  }
   190  
   191  func (qt *Test) writeTestData(ctx context.Context, t *testing.T, c *tests.Client) {
   192  	t.Helper()
   193  	for _, w := range qt.writes {
   194  		bucketID := &qt.bucketID
   195  		if w.bucketID != 0 {
   196  			bucketID = &w.bucketID
   197  		}
   198  		err := c.WriteTo(ctx, influxdb.BucketFilter{ID: bucketID, OrganizationID: &qt.orgID}, strings.NewReader(w.data))
   199  		require.NoError(t, err)
   200  	}
   201  }
   202  
   203  func maxInt64() string {
   204  	maxInt64, _ := json.Marshal(^int64(0))
   205  	return string(maxInt64)
   206  }
   207  
   208  func now() time.Time {
   209  	return time.Now().UTC()
   210  }
   211  
   212  func yesterday() time.Time {
   213  	return now().Add(-1 * time.Hour * 24)
   214  }
   215  
   216  func mustParseTime(layout, value string) time.Time {
   217  	tm, err := time.Parse(layout, value)
   218  	if err != nil {
   219  		panic(err)
   220  	}
   221  	return tm
   222  }
   223  
   224  func mustParseLocation(tzname string) *time.Location {
   225  	loc, err := time.LoadLocation(tzname)
   226  	if err != nil {
   227  		panic(err)
   228  	}
   229  	return loc
   230  }
   231  
   232  var LosAngeles = mustParseLocation("America/Los_Angeles")