github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/ts/query_test.go (about)

     1  // Copyright 2015 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package ts
    12  
    13  import (
    14  	"context"
    15  	"math"
    16  	"runtime"
    17  	"testing"
    18  	"time"
    19  
    20  	"github.com/cockroachdb/cockroach/pkg/settings/cluster"
    21  	"github.com/cockroachdb/cockroach/pkg/ts/tspb"
    22  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    23  	"github.com/cockroachdb/cockroach/pkg/util/mon"
    24  )
    25  
    26  // runTestCaseMultipleFormats runs the provided test case body against a
    27  // testModelRunner configured to run in row format, and then again against a
    28  // cluster configured to run in column format.
    29  func runTestCaseMultipleFormats(t *testing.T, testCase func(*testing.T, testModelRunner)) {
    30  	t.Run("Row Format", func(t *testing.T) {
    31  		tm := newTestModelRunner(t)
    32  		tm.Start()
    33  		tm.DB.forceRowFormat = true
    34  		defer tm.Stop()
    35  		testCase(t, tm)
    36  	})
    37  
    38  	t.Run("Column Format", func(t *testing.T) {
    39  		tm := newTestModelRunner(t)
    40  		tm.Start()
    41  		defer tm.Stop()
    42  		testCase(t, tm)
    43  	})
    44  }
    45  
    46  // TestQueryBasic validates that query results match the expectation of the test
    47  // model in basic situations.
    48  func TestQueryBasic(t *testing.T) {
    49  	defer leaktest.AfterTest(t)()
    50  	runTestCaseMultipleFormats(t, func(t *testing.T, tm testModelRunner) {
    51  		tm.storeTimeSeriesData(resolution1ns, []tspb.TimeSeriesData{
    52  			tsd("test.metric", "",
    53  				tsdp(1, 100),
    54  				tsdp(5, 200),
    55  				tsdp(15, 300),
    56  				tsdp(16, 400),
    57  				tsdp(17, 500),
    58  				tsdp(22, 600),
    59  				tsdp(52, 900),
    60  			),
    61  		})
    62  		tm.assertKeyCount(4)
    63  		tm.assertModelCorrect()
    64  
    65  		query := tm.makeQuery("test.metric", resolution1ns, 0, 60)
    66  		query.assertSuccess(7, 1)
    67  
    68  		// Verify across multiple sources
    69  		tm.storeTimeSeriesData(resolution1ns, []tspb.TimeSeriesData{
    70  			tsd("test.multimetric", "source1",
    71  				tsdp(1, 100),
    72  				tsdp(15, 300),
    73  				tsdp(17, 500),
    74  				tsdp(52, 900),
    75  			),
    76  			tsd("test.multimetric", "source2",
    77  				tsdp(5, 100),
    78  				tsdp(16, 300),
    79  				tsdp(22, 500),
    80  				tsdp(82, 900),
    81  			),
    82  		})
    83  
    84  		tm.assertKeyCount(11)
    85  		tm.assertModelCorrect()
    86  
    87  		// Test default query: avg downsampler, sum aggregator, no derivative.
    88  		query = tm.makeQuery("test.multimetric", resolution1ns, 0, 90)
    89  		query.assertSuccess(8, 2)
    90  		// Test with aggregator specified.
    91  		query.setSourceAggregator(tspb.TimeSeriesQueryAggregator_MAX)
    92  		query.assertSuccess(8, 2)
    93  		// Test with aggregator and downsampler.
    94  		query.setDownsampler(tspb.TimeSeriesQueryAggregator_AVG)
    95  		query.assertSuccess(8, 2)
    96  		// Test with derivative specified.
    97  		query.Downsampler = nil
    98  		query.setDerivative(tspb.TimeSeriesQueryDerivative_DERIVATIVE)
    99  		query.assertSuccess(7, 2)
   100  		// Test with everything specified.
   101  		query = tm.makeQuery("test.multimetric", resolution1ns, 0, 90)
   102  		query.setSourceAggregator(tspb.TimeSeriesQueryAggregator_MIN)
   103  		query.setDownsampler(tspb.TimeSeriesQueryAggregator_MAX)
   104  		query.setDerivative(tspb.TimeSeriesQueryDerivative_NON_NEGATIVE_DERIVATIVE)
   105  		query.assertSuccess(7, 2)
   106  
   107  		// Test queries that return no data. Check with every
   108  		// aggregator/downsampler/derivative combination. This situation is
   109  		// particularly prone to nil panics (parts of the query system will not have
   110  		// data).
   111  		aggs := []tspb.TimeSeriesQueryAggregator{
   112  			tspb.TimeSeriesQueryAggregator_MIN, tspb.TimeSeriesQueryAggregator_MAX,
   113  			tspb.TimeSeriesQueryAggregator_AVG, tspb.TimeSeriesQueryAggregator_SUM,
   114  		}
   115  		derivs := []tspb.TimeSeriesQueryDerivative{
   116  			tspb.TimeSeriesQueryDerivative_NONE, tspb.TimeSeriesQueryDerivative_DERIVATIVE,
   117  			tspb.TimeSeriesQueryDerivative_NON_NEGATIVE_DERIVATIVE,
   118  		}
   119  		query = tm.makeQuery("nodata", resolution1ns, 0, 90)
   120  		for _, downsampler := range aggs {
   121  			for _, agg := range aggs {
   122  				for _, deriv := range derivs {
   123  					query.setDownsampler(downsampler)
   124  					query.setSourceAggregator(agg)
   125  					query.setDerivative(deriv)
   126  					query.assertSuccess(0, 0)
   127  				}
   128  			}
   129  		}
   130  
   131  		// Verify querying specific sources, thus excluding other available sources
   132  		// in the same time period.
   133  		tm.storeTimeSeriesData(resolution1ns, []tspb.TimeSeriesData{
   134  			tsd("test.specificmetric", "source1",
   135  				tsdp(1, 9999),
   136  				tsdp(11, 9999),
   137  				tsdp(21, 9999),
   138  				tsdp(31, 9999),
   139  			),
   140  			tsd("test.specificmetric", "source2",
   141  				tsdp(2, 10),
   142  				tsdp(12, 15),
   143  				tsdp(22, 25),
   144  				tsdp(32, 60),
   145  			),
   146  			tsd("test.specificmetric", "source3",
   147  				tsdp(3, 9999),
   148  				tsdp(13, 9999),
   149  				tsdp(23, 9999),
   150  				tsdp(33, 9999),
   151  			),
   152  			tsd("test.specificmetric", "source4",
   153  				tsdp(4, 15),
   154  				tsdp(14, 45),
   155  				tsdp(24, 60),
   156  				tsdp(32, 100),
   157  			),
   158  			tsd("test.specificmetric", "source5",
   159  				tsdp(5, 9999),
   160  				tsdp(15, 9999),
   161  				tsdp(25, 9999),
   162  				tsdp(35, 9999),
   163  			),
   164  		})
   165  
   166  		tm.assertKeyCount(31)
   167  		tm.assertModelCorrect()
   168  
   169  		// Assert querying data from subset of sources. Includes source with no
   170  		// data.
   171  		query = tm.makeQuery("test.specificmetric", resolution1ns, 0, 90)
   172  		query.Sources = []string{"source2", "source4", "source6"}
   173  		query.assertSuccess(7, 2)
   174  
   175  		// Assert querying data over limited range for single source. Regression
   176  		// test for #4987.
   177  		query.Sources = []string{"source4", "source5"}
   178  		query.QueryTimespan = QueryTimespan{
   179  			StartNanos:          5,
   180  			EndNanos:            24,
   181  			SampleDurationNanos: 1,
   182  			NowNanos:            math.MaxInt64,
   183  		}
   184  		query.assertSuccess(4, 2)
   185  	})
   186  }
   187  
   188  // TestQueryDownsampling validates that query results match the expectation of
   189  // the test model.
   190  func TestQueryDownsampling(t *testing.T) {
   191  	defer leaktest.AfterTest(t)()
   192  	runTestCaseMultipleFormats(t, func(t *testing.T, tm testModelRunner) {
   193  		// Query with sampleDuration that is too small, expect error.
   194  		{
   195  			query := tm.makeQuery("", Resolution10s, 0, 10000)
   196  			query.SampleDurationNanos = 1
   197  			query.assertError("was not less")
   198  
   199  			// Query with sampleDuration which is not an even multiple of the resolution.
   200  			query.SampleDurationNanos = Resolution10s.SampleDuration() + 1
   201  			query.assertError("not a multiple")
   202  		}
   203  
   204  		tm.storeTimeSeriesData(resolution1ns, []tspb.TimeSeriesData{
   205  			tsd("test.metric", "source1",
   206  				tsdp(1, 100),
   207  				tsdp(5, 500),
   208  				tsdp(15, 500),
   209  				tsdp(16, 600),
   210  				tsdp(17, 700),
   211  				tsdp(22, 200),
   212  				tsdp(45, 500),
   213  				tsdp(46, 600),
   214  				tsdp(52, 200),
   215  			),
   216  			tsd("test.metric", "source2",
   217  				tsdp(7, 0),
   218  				tsdp(7, 700),
   219  				tsdp(9, 900),
   220  				tsdp(14, 400),
   221  				tsdp(18, 800),
   222  				tsdp(33, 300),
   223  				tsdp(34, 400),
   224  				tsdp(56, 600),
   225  				tsdp(59, 900),
   226  			),
   227  		})
   228  		tm.assertKeyCount(9)
   229  		tm.assertModelCorrect()
   230  
   231  		{
   232  			query := tm.makeQuery("test.metric", resolution1ns, 0, 60)
   233  			query.SampleDurationNanos = 10
   234  			query.assertSuccess(6, 2)
   235  
   236  			query.Sources = []string{"source1"}
   237  			query.assertSuccess(5, 1)
   238  
   239  			query.Sources = []string{"source2"}
   240  			query.assertSuccess(4, 1)
   241  
   242  			query.Sources = nil
   243  			query.SampleDurationNanos = 50
   244  			query.assertSuccess(2, 2)
   245  		}
   246  
   247  		// Query boundaries don't align to downsample period.
   248  		{
   249  			query := tm.makeQuery("test.metric", resolution1ns, 15, 35)
   250  			query.SampleDurationNanos = 10
   251  			query.assertSuccess(3, 2)
   252  		}
   253  	})
   254  }
   255  
   256  // TestInterpolationLimit validates that query results match the expectation of
   257  // the test model.
   258  func TestInterpolationLimit(t *testing.T) {
   259  	defer leaktest.AfterTest(t)()
   260  	runTestCaseMultipleFormats(t, func(t *testing.T, tm testModelRunner) {
   261  		// Metric with gaps at the edge of a queryable range.
   262  		// The first source has missing data points at 14 and 19, which can
   263  		// be interpolated from data points located in nearby slabs.
   264  		// 5 - [15, 16, 17, 18] - 25
   265  		tm.storeTimeSeriesData(resolution1ns, []tspb.TimeSeriesData{
   266  			tsd("metric.edgegaps", "source1",
   267  				tsdp(5, 500),
   268  				tsdp(15, 1500),
   269  				tsdp(16, 1600),
   270  				tsdp(17, 1700),
   271  				tsdp(18, 1800),
   272  				tsdp(25, 2500),
   273  			),
   274  			tsd("metric.edgegaps", "source2",
   275  				tsdp(14, 1000),
   276  				tsdp(15, 1000),
   277  				tsdp(16, 1000),
   278  				tsdp(17, 1000),
   279  				tsdp(18, 1000),
   280  				tsdp(19, 1000),
   281  			),
   282  		})
   283  		tm.assertKeyCount(4)
   284  		tm.assertModelCorrect()
   285  
   286  		{
   287  			query := tm.makeQuery("metric.edgegaps", resolution1ns, 14, 19)
   288  			query.assertSuccess(6, 2)
   289  			query.InterpolationLimitNanos = 10
   290  			query.assertSuccess(6, 2)
   291  			query.Sources = []string{"source1", "source2"}
   292  			query.assertSuccess(6, 2)
   293  		}
   294  
   295  		// Metric with inner gaps which may be effected by the interpolation limit.
   296  		tm.storeTimeSeriesData(resolution1ns, []tspb.TimeSeriesData{
   297  			tsd("metric.innergaps", "source1",
   298  				tsdp(1, 100),
   299  				tsdp(2, 200),
   300  				tsdp(4, 400),
   301  				tsdp(7, 700),
   302  				tsdp(10, 1000),
   303  			),
   304  			tsd("metric.innergaps", "source2",
   305  				tsdp(1, 100),
   306  				tsdp(2, 100),
   307  				tsdp(3, 100),
   308  				tsdp(4, 100),
   309  				tsdp(5, 100),
   310  				tsdp(6, 100),
   311  				tsdp(7, 100),
   312  				tsdp(8, 100),
   313  				tsdp(9, 100),
   314  			),
   315  		})
   316  		tm.assertKeyCount(7)
   317  		tm.assertModelCorrect()
   318  
   319  		// Interpolation limit 0, 2, 3, and 10.
   320  		{
   321  			query := tm.makeQuery("metric.innergaps", resolution1ns, 0, 9)
   322  			query.assertSuccess(9, 2)
   323  			query.InterpolationLimitNanos = 2
   324  			query.assertSuccess(9, 2)
   325  			query.InterpolationLimitNanos = 3
   326  			query.assertSuccess(9, 2)
   327  			query.InterpolationLimitNanos = 10
   328  			query.assertSuccess(9, 2)
   329  		}
   330  
   331  		// With explicit source list.
   332  		{
   333  			query := tm.makeQuery("metric.innergaps", resolution1ns, 0, 9)
   334  			query.Sources = []string{"source1", "source2"}
   335  			query.assertSuccess(9, 2)
   336  			query.InterpolationLimitNanos = 2
   337  			query.assertSuccess(9, 2)
   338  			query.InterpolationLimitNanos = 3
   339  			query.assertSuccess(9, 2)
   340  			query.InterpolationLimitNanos = 10
   341  			query.assertSuccess(9, 2)
   342  		}
   343  
   344  		// With derivative.
   345  		{
   346  			query := tm.makeQuery("metric.innergaps", resolution1ns, 0, 9)
   347  			query.Sources = []string{"source1", "source2"}
   348  			query.setDerivative(tspb.TimeSeriesQueryDerivative_DERIVATIVE)
   349  			query.assertSuccess(8, 2)
   350  			query.InterpolationLimitNanos = 2
   351  			query.assertSuccess(8, 2)
   352  			query.InterpolationLimitNanos = 3
   353  			query.assertSuccess(8, 2)
   354  			query.InterpolationLimitNanos = 10
   355  			query.assertSuccess(8, 2)
   356  		}
   357  	})
   358  }
   359  
   360  func TestQueryWorkerMemoryConstraint(t *testing.T) {
   361  	defer leaktest.AfterTest(t)()
   362  	runTestCaseMultipleFormats(t, func(t *testing.T, tm testModelRunner) {
   363  		generateData := func(dps int64) []tspb.TimeSeriesDatapoint {
   364  			result := make([]tspb.TimeSeriesDatapoint, 0, dps)
   365  			var i int64
   366  			for i = 0; i < dps; i++ {
   367  				result = append(result, tsdp(time.Duration(i), float64(100*i)))
   368  			}
   369  			return result
   370  		}
   371  
   372  		// Store data for a large metric across many keys, so we can test across
   373  		// many different memory maximums.
   374  		tm.storeTimeSeriesData(resolution1ns, []tspb.TimeSeriesData{
   375  			tsd(
   376  				"test.metric",
   377  				"source1",
   378  				generateData(120)...,
   379  			),
   380  			tsd(
   381  				"test.metric",
   382  				"source2",
   383  				generateData(120)...,
   384  			),
   385  			tsd(
   386  				"test.metric",
   387  				"source3",
   388  				generateData(120)...,
   389  			),
   390  		})
   391  		tm.assertKeyCount(36)
   392  		tm.assertModelCorrect()
   393  
   394  		// Track the total maximum memory used for a query with no budget.
   395  		{
   396  			// Swap model's memory monitor in order to adjust allocation size.
   397  			adjustedMon := mon.MakeMonitor(
   398  				"timeseries-test-worker-adjusted",
   399  				mon.MemoryResource,
   400  				nil,
   401  				nil,
   402  				1,
   403  				math.MaxInt64,
   404  				cluster.MakeTestingClusterSettings(),
   405  			)
   406  			adjustedMon.Start(context.Background(), tm.workerMemMonitor, mon.BoundAccount{})
   407  			defer adjustedMon.Stop(context.Background())
   408  
   409  			query := tm.makeQuery("test.metric", resolution1ns, 11, 109)
   410  			query.workerMemMonitor = &adjustedMon
   411  			query.InterpolationLimitNanos = 10
   412  			query.assertSuccess(99, 3)
   413  			memoryUsed := adjustedMon.MaximumBytes()
   414  
   415  			for _, limit := range []int64{
   416  				memoryUsed,
   417  				memoryUsed / 2,
   418  				memoryUsed / 3,
   419  			} {
   420  				// Limit memory in use by model. Reset memory monitor to get new maximum.
   421  				adjustedMon.Stop(context.Background())
   422  				adjustedMon.Start(context.Background(), tm.workerMemMonitor, mon.BoundAccount{})
   423  				if adjustedMon.MaximumBytes() != 0 {
   424  					t.Fatalf("maximum bytes was %d, wanted zero", adjustedMon.MaximumBytes())
   425  				}
   426  
   427  				query.BudgetBytes = limit
   428  				query.assertSuccess(99, 3)
   429  
   430  				// Expected maximum usage may slightly exceed the budget due to the size of
   431  				// dataSpan structures which are not accounted for in getMaxTimespan.
   432  				if a, e := adjustedMon.MaximumBytes(), limit; a > e {
   433  					t.Fatalf("memory usage for query was %d, exceeded set maximum limit %d", a, e)
   434  				}
   435  
   436  				// As an additional check, ensure that maximum bytes used was within 5% of memory budget;
   437  				// we want to use as much memory as we can to ensure the fastest possible queries.
   438  				if a, e := float64(adjustedMon.MaximumBytes()), float64(limit)*0.95; a < e {
   439  					t.Fatalf("memory usage for query was %f, wanted at least %f", a, e)
   440  				}
   441  			}
   442  		}
   443  
   444  		// Verify insufficient memory error bubbles up.
   445  		{
   446  			query := tm.makeQuery("test.metric", resolution1ns, 0, 10000)
   447  			query.BudgetBytes = 1000
   448  			query.EstimatedSources = 3
   449  			query.InterpolationLimitNanos = 5
   450  			query.assertError("insufficient")
   451  		}
   452  	})
   453  }
   454  
   455  func TestQueryWorkerMemoryMonitor(t *testing.T) {
   456  	defer leaktest.AfterTest(t)()
   457  	runTestCaseMultipleFormats(t, func(t *testing.T, tm testModelRunner) {
   458  		tm.storeTimeSeriesData(resolution1ns, []tspb.TimeSeriesData{
   459  			tsd("test.metric", "",
   460  				tsdp(1, 100),
   461  				tsdp(5, 200),
   462  				tsdp(15, 300),
   463  				tsdp(16, 400),
   464  				tsdp(17, 500),
   465  				tsdp(22, 600),
   466  				tsdp(52, 900),
   467  			),
   468  		})
   469  		tm.assertKeyCount(4)
   470  		tm.assertModelCorrect()
   471  
   472  		// Create a limited bytes monitor.
   473  		memoryBudget := int64(100 * 1024)
   474  		limitedMon := mon.MakeMonitorWithLimit(
   475  			"timeseries-test-limited",
   476  			mon.MemoryResource,
   477  			memoryBudget,
   478  			nil,
   479  			nil,
   480  			100,
   481  			100,
   482  			cluster.MakeTestingClusterSettings(),
   483  		)
   484  		limitedMon.Start(context.Background(), tm.workerMemMonitor, mon.BoundAccount{})
   485  		defer limitedMon.Stop(context.Background())
   486  
   487  		// Assert correctness with no memory pressure.
   488  		query := tm.makeQuery("test.metric", resolution1ns, 0, 60)
   489  		query.workerMemMonitor = &limitedMon
   490  		query.assertSuccess(7, 1)
   491  
   492  		// Assert failure with memory pressure.
   493  		acc := limitedMon.MakeBoundAccount()
   494  		if err := acc.Grow(context.Background(), memoryBudget-1); err != nil {
   495  			t.Fatal(err)
   496  		}
   497  
   498  		query.assertError("memory budget exceeded")
   499  
   500  		// Assert success again with memory pressure released.
   501  		acc.Close(context.Background())
   502  		query.assertSuccess(7, 1)
   503  
   504  		// Start/Stop limited monitor to reset maximum allocation.
   505  		limitedMon.Stop(context.Background())
   506  		limitedMon.Start(context.Background(), tm.workerMemMonitor, mon.BoundAccount{})
   507  
   508  		var (
   509  			memStatsBefore runtime.MemStats
   510  			memStatsAfter  runtime.MemStats
   511  		)
   512  		runtime.ReadMemStats(&memStatsBefore)
   513  
   514  		query.EndNanos = 10000
   515  		query.assertSuccess(7, 1)
   516  
   517  		runtime.ReadMemStats(&memStatsAfter)
   518  		t.Logf("total allocations for query: %d\n", memStatsAfter.TotalAlloc-memStatsBefore.TotalAlloc)
   519  		t.Logf("maximum allocations for query monitor: %d\n", limitedMon.MaximumBytes())
   520  	})
   521  }
   522  
   523  // TestQueryBadRequests confirms that the query method returns gentle errors for
   524  // obviously bad incoming data.
   525  func TestQueryBadRequests(t *testing.T) {
   526  	defer leaktest.AfterTest(t)()
   527  	runTestCaseMultipleFormats(t, func(t *testing.T, tm testModelRunner) {
   528  		// Query with a downsampler that is invalid, expect error.
   529  		{
   530  			query := tm.makeQuery("metric.test", resolution1ns, 0, 10000)
   531  			query.SampleDurationNanos = 10
   532  			query.setDownsampler((tspb.TimeSeriesQueryAggregator)(999))
   533  			query.assertError("unknown time series downsampler")
   534  		}
   535  
   536  		// Query with a aggregator that is invalid, expect error.
   537  		{
   538  			query := tm.makeQuery("metric.test", resolution1ns, 0, 10000)
   539  			query.SampleDurationNanos = 10
   540  			query.setSourceAggregator((tspb.TimeSeriesQueryAggregator)(999))
   541  			query.assertError("unknown time series aggregator")
   542  		}
   543  
   544  		// Query with a downsampler that is invalid, expect no error (default behavior is none).
   545  		{
   546  			query := tm.makeQuery("metric.test", resolution1ns, 0, 10000)
   547  			query.SampleDurationNanos = 10
   548  			query.setDerivative((tspb.TimeSeriesQueryDerivative)(999))
   549  			query.assertSuccess(0, 0)
   550  		}
   551  	})
   552  }
   553  
   554  func TestQueryNearCurrentTime(t *testing.T) {
   555  	defer leaktest.AfterTest(t)()
   556  	runTestCaseMultipleFormats(t, func(t *testing.T, tm testModelRunner) {
   557  		tm.storeTimeSeriesData(resolution1ns, []tspb.TimeSeriesData{
   558  			tsd("metric.test", "source1",
   559  				tsdp(1, 100),
   560  				tsdp(5, 500),
   561  				tsdp(15, 500),
   562  				tsdp(16, 600),
   563  				tsdp(17, 700),
   564  				tsdp(22, 200),
   565  				tsdp(45, 500),
   566  				tsdp(46, 600),
   567  				tsdp(52, 200),
   568  			),
   569  			tsd("metric.test", "source2",
   570  				tsdp(7, 0),
   571  				tsdp(7, 700),
   572  				tsdp(9, 900),
   573  				tsdp(14, 400),
   574  				tsdp(18, 800),
   575  				tsdp(33, 300),
   576  				tsdp(34, 400),
   577  				tsdp(56, 600),
   578  				tsdp(59, 900),
   579  			),
   580  		})
   581  		tm.assertKeyCount(9)
   582  		tm.assertModelCorrect()
   583  
   584  		// All points returned for query with nowNanos in the future.
   585  		{
   586  			query := tm.makeQuery("metric.test", resolution1ns, 0, 500)
   587  			query.NowNanos = 60
   588  			query.assertSuccess(17, 2)
   589  		}
   590  
   591  		// Test query is disallowed in the future.
   592  		{
   593  			query := tm.makeQuery("metric.test", resolution1ns, 20, 500)
   594  			query.NowNanos = 10
   595  			query.assertError("cannot query time series in the future")
   596  		}
   597  
   598  		// Test query is truncated so that future datapoints are not queried.
   599  		{
   600  			query := tm.makeQuery("metric.test", resolution1ns, 0, 500)
   601  			query.NowNanos = 30
   602  			query.assertSuccess(10, 2)
   603  		}
   604  
   605  		// Data points from incomplete periods are not included.
   606  		{
   607  			query := tm.makeQuery("metric.test", resolution1ns, 0, 500)
   608  			query.NowNanos = 59
   609  			query.assertSuccess(16, 2)
   610  		}
   611  
   612  		// Data points for incomplete periods are not included (with downsampling).
   613  		{
   614  			query := tm.makeQuery("metric.test", resolution1ns, 0, 500)
   615  			query.NowNanos = 60
   616  			query.SampleDurationNanos = 10
   617  			query.assertSuccess(6, 2)
   618  
   619  			query = tm.makeQuery("metric.test", resolution1ns, 0, 500)
   620  			query.NowNanos = 59
   621  			query.SampleDurationNanos = 10
   622  			query.assertSuccess(5, 2)
   623  		}
   624  	})
   625  }
   626  
   627  func TestQueryRollup(t *testing.T) {
   628  	defer leaktest.AfterTest(t)()
   629  
   630  	// Rollups are always columnar, no need to run this test using row format.
   631  	tm := newTestModelRunner(t)
   632  	tm.Start()
   633  	defer tm.Stop()
   634  
   635  	tm.storeTimeSeriesData(resolution50ns, []tspb.TimeSeriesData{
   636  		tsd("metric.test", "source1",
   637  			tsdp(1, 100),
   638  			tsdp(45, 500),
   639  			tsdp(150, 500),
   640  			tsdp(165, 600),
   641  			tsdp(172, 700),
   642  			tsdp(220, 200),
   643  			tsdp(230, 200),
   644  			tsdp(240, 242),
   645  			tsdp(350, 500),
   646  			tsdp(520, 199),
   647  			tsdp(610, 200),
   648  			tsdp(620, 999),
   649  			tsdp(750, 200),
   650  			tsdp(751, 2123),
   651  			tsdp(921, 500),
   652  			tsdp(991, 500),
   653  			tsdp(1001, 1234),
   654  			tsdp(1002, 234),
   655  		),
   656  		tsd("metric.test", "source2",
   657  			tsdp(7, 234),
   658  			tsdp(63, 342),
   659  			tsdp(74, 342),
   660  			tsdp(124, 500),
   661  			tsdp(186, 2345),
   662  			tsdp(193, 1234),
   663  			tsdp(220, 200),
   664  			tsdp(221, 200),
   665  			tsdp(240, 22342),
   666  			tsdp(420, 975),
   667  			tsdp(422, 396),
   668  			tsdp(498, 6884.74),
   669  			tsdp(610, 200),
   670  			tsdp(620, 999),
   671  			tsdp(750, 200),
   672  			tsdp(751, 2123),
   673  			tsdp(854, 9403),
   674  			tsdp(921, 500),
   675  			tsdp(991, 500),
   676  			tsdp(1001, 1234),
   677  			tsdp(1002, 234),
   678  		),
   679  	})
   680  	tm.assertKeyCount(4)
   681  	tm.assertModelCorrect()
   682  
   683  	{
   684  		query := tm.makeQuery("metric.test", resolution50ns, 100, 1500)
   685  		query.assertSuccess(13, 2)
   686  	}
   687  
   688  	{
   689  		query := tm.makeQuery("metric.test", resolution50ns, 450, 850)
   690  		query.setDownsampler(tspb.TimeSeriesQueryAggregator_MAX)
   691  		query.setDownsampler(tspb.TimeSeriesQueryAggregator_MIN)
   692  		query.assertSuccess(5, 2)
   693  	}
   694  
   695  	{
   696  		query := tm.makeQuery("metric.test", resolution50ns, 100, 1500)
   697  		query.setDerivative(tspb.TimeSeriesQueryDerivative_DERIVATIVE)
   698  		query.assertSuccess(13, 2)
   699  	}
   700  }