github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/dbnode/integration/query_limit_test.go (about)

     1  // +build integration
     2  
     3  // Copyright (c) 2020 Uber Technologies, Inc.
     4  //
     5  // Permission is hereby granted, free of charge, to any person obtaining a copy
     6  // of this software and associated documentation files (the "Software"), to deal
     7  // in the Software without restriction, including without limitation the rights
     8  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     9  // copies of the Software, and to permit persons to whom the Software is
    10  // furnished to do so, subject to the following conditions:
    11  //
    12  // The above copyright notice and this permission notice shall be included in
    13  // all copies or substantial portions of the Software.
    14  //
    15  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    16  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    17  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    18  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    19  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    20  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    21  // THE SOFTWARE.
    22  
    23  package integration
    24  
    25  import (
    26  	"fmt"
    27  	"testing"
    28  	"time"
    29  
    30  	"github.com/stretchr/testify/require"
    31  
    32  	"github.com/m3db/m3/src/dbnode/client"
    33  	"github.com/m3db/m3/src/dbnode/namespace"
    34  	"github.com/m3db/m3/src/dbnode/storage"
    35  	"github.com/m3db/m3/src/dbnode/storage/index"
    36  	"github.com/m3db/m3/src/dbnode/storage/limits"
    37  	"github.com/m3db/m3/src/m3ninx/idx"
    38  	"github.com/m3db/m3/src/x/ident"
    39  	xtime "github.com/m3db/m3/src/x/time"
    40  )
    41  
    42  func TestQueryLimitExceededError(t *testing.T) {
    43  	testOpts, ns := newTestOptionsWithIndexedNamespace(t)
    44  	testSetup := newTestSetupWithQueryLimits(t, testOpts)
    45  	defer testSetup.Close()
    46  
    47  	require.NoError(t, testSetup.StartServer())
    48  	defer func() {
    49  		require.NoError(t, testSetup.StopServer())
    50  	}()
    51  
    52  	var (
    53  		nowFn     = testSetup.StorageOpts().ClockOptions().NowFn()
    54  		end       = xtime.ToUnixNano(nowFn().Truncate(time.Hour))
    55  		start     = end.Add(-time.Hour)
    56  		query     = index.Query{Query: idx.NewTermQuery([]byte("tag"), []byte("value"))}
    57  		queryOpts = index.QueryOptions{StartInclusive: start, EndExclusive: end}
    58  		aggOpts   = index.AggregationOptions{QueryOptions: queryOpts}
    59  	)
    60  
    61  	session, err := testSetup.M3DBClient().DefaultSession()
    62  	require.NoError(t, err)
    63  
    64  	for i := 0; i < 2; i++ {
    65  		var (
    66  			metricName = fmt.Sprintf("metric_%v", i)
    67  			tags       = ident.StringTag("tag", "value")
    68  			timestamp  = xtime.ToUnixNano(nowFn()).Add(-time.Minute * time.Duration(i+1))
    69  		)
    70  		err := session.WriteTagged(ns.ID(), ident.StringID(metricName),
    71  			ident.NewTagsIterator(ident.NewTags(tags)), timestamp, 0.0, xtime.Second, nil)
    72  		require.NoError(t, err)
    73  	}
    74  
    75  	_, _, err = session.FetchTagged(ContextWithDefaultTimeout(),
    76  		ns.ID(), query, queryOpts)
    77  	require.True(t, client.IsResourceExhaustedError(err),
    78  		"expected resource exhausted error, got: %v", err)
    79  
    80  	_, _, err = session.Aggregate(ContextWithDefaultTimeout(), ns.ID(), query, aggOpts)
    81  	require.True(t, client.IsResourceExhaustedError(err),
    82  		"expected aggregate resource exhausted error, got: %v", err)
    83  
    84  }
    85  
    86  func newTestOptionsWithIndexedNamespace(t *testing.T) (TestOptions, namespace.Metadata) {
    87  	idxOpts := namespace.NewIndexOptions().SetEnabled(true)
    88  	nsOpts := namespace.NewOptions().SetIndexOptions(idxOpts)
    89  	ns, err := namespace.NewMetadata(testNamespaces[0], nsOpts)
    90  	require.NoError(t, err)
    91  
    92  	testOpts := NewTestOptions(t).SetNamespaces([]namespace.Metadata{ns})
    93  	return testOpts, ns
    94  }
    95  
    96  func newTestSetupWithQueryLimits(t *testing.T, opts TestOptions) TestSetup {
    97  	storageLimitsFn := func(storageOpts storage.Options) storage.Options {
    98  		queryLookback := limits.DefaultLookbackLimitOptions()
    99  		queryLookback.Limit = 1
   100  		queryLookback.Lookback = time.Hour
   101  
   102  		limitOpts := limits.NewOptions().
   103  			SetBytesReadLimitOpts(queryLookback).
   104  			SetDocsLimitOpts(queryLookback).
   105  			SetAggregateDocsLimitOpts(queryLookback).
   106  			SetInstrumentOptions(storageOpts.InstrumentOptions())
   107  		queryLimits, err := limits.NewQueryLimits(limitOpts)
   108  		require.NoError(t, err)
   109  
   110  		indexOpts := storageOpts.IndexOptions().SetQueryLimits(queryLimits)
   111  		return storageOpts.SetIndexOptions(indexOpts)
   112  	}
   113  
   114  	setup, err := NewTestSetup(t, opts, nil, storageLimitsFn)
   115  	require.NoError(t, err)
   116  
   117  	return setup
   118  }