github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/query/executor/transform/exec_test.go (about)

     1  // Copyright (c) 2019 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package transform
    22  
    23  import (
    24  	"context"
    25  	"errors"
    26  	"testing"
    27  	"time"
    28  
    29  	"github.com/m3db/m3/src/query/block"
    30  	"github.com/m3db/m3/src/query/functions/utils"
    31  	"github.com/m3db/m3/src/query/models"
    32  	"github.com/m3db/m3/src/query/parser"
    33  	"github.com/m3db/m3/src/query/test"
    34  	xtest "github.com/m3db/m3/src/x/test"
    35  
    36  	"github.com/golang/mock/gomock"
    37  	"github.com/opentracing/opentracing-go"
    38  	"github.com/opentracing/opentracing-go/mocktracer"
    39  	"github.com/stretchr/testify/assert"
    40  	"github.com/stretchr/testify/require"
    41  )
    42  
    43  func TestProcessSimpleBlock(t *testing.T) {
    44  	type testContext struct {
    45  		MockCtrl    *gomock.Controller
    46  		Controller  *Controller
    47  		ChildNode   *MockOpNode
    48  		Node        *MocksimpleOpNode
    49  		ResultBlock *block.MockBlock
    50  		SourceBlock block.Block
    51  		QueryCtx    *models.QueryContext
    52  	}
    53  
    54  	setup := func(t *testing.T) (*testContext, func()) {
    55  		ctrl := xtest.NewController(t)
    56  
    57  		controller := &Controller{
    58  			ID: parser.NodeID("foo"),
    59  		}
    60  		child := NewMockOpNode(ctrl)
    61  		controller.AddTransform(child)
    62  
    63  		step := time.Second
    64  		bounds := models.Bounds{
    65  			StepSize: step,
    66  			Duration: step,
    67  		}
    68  
    69  		return &testContext{
    70  			MockCtrl:    ctrl,
    71  			Controller:  controller,
    72  			SourceBlock: test.NewBlockFromValues(bounds, [][]float64{{1.0}}),
    73  			ResultBlock: block.NewMockBlock(ctrl),
    74  			Node:        NewMocksimpleOpNode(ctrl),
    75  			ChildNode:   child,
    76  			QueryCtx:    models.NoopQueryContext(),
    77  		}, ctrl.Finish
    78  	}
    79  
    80  	doCall := func(tctx *testContext) error {
    81  		return ProcessSimpleBlock(tctx.Node, tctx.Controller, tctx.QueryCtx, tctx.Controller.ID, tctx.SourceBlock)
    82  	}
    83  
    84  	configureNode := func(
    85  		tctx *testContext,
    86  		blockType block.BlockType,
    87  		closeExpected bool,
    88  	) {
    89  		tctx.Node.EXPECT().Params().Return(utils.StaticParams("foo"))
    90  		tctx.Node.EXPECT().ProcessBlock(gomock.Any(), gomock.Any(), gomock.Any()).Return(tctx.ResultBlock, nil)
    91  		tctx.ChildNode.EXPECT().Process(gomock.Any(), gomock.Any(), gomock.Any())
    92  		tctx.ResultBlock.EXPECT().Info().Return(block.NewBlockInfo(blockType))
    93  		if closeExpected {
    94  			tctx.ResultBlock.EXPECT().Close()
    95  		}
    96  	}
    97  
    98  	configureSuccessfulNode := func(tctx *testContext) {
    99  		configureNode(tctx, block.BlockM3TSZCompressed, true)
   100  	}
   101  
   102  	t.Run("closes next block", func(t *testing.T) {
   103  		tctx, closer := setup(t)
   104  		defer closer()
   105  
   106  		configureSuccessfulNode(tctx)
   107  
   108  		require.NoError(t, doCall(tctx))
   109  	})
   110  
   111  	configureLazyNode := func(tctx *testContext) {
   112  		configureNode(tctx, block.BlockLazy, false)
   113  	}
   114  
   115  	t.Run("does not close lazy block", func(t *testing.T) {
   116  		tctx, closer := setup(t)
   117  		defer closer()
   118  
   119  		configureLazyNode(tctx)
   120  
   121  		require.NoError(t, doCall(tctx))
   122  	})
   123  
   124  	t.Run("errors on process error", func(t *testing.T) {
   125  		tctx, closer := setup(t)
   126  		defer closer()
   127  
   128  		expectedErr := errors.New("test err")
   129  		tctx.Node.EXPECT().Params().Return(utils.StaticParams("foo"))
   130  		tctx.Node.EXPECT().ProcessBlock(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, expectedErr)
   131  
   132  		require.EqualError(t, doCall(tctx), expectedErr.Error())
   133  	})
   134  
   135  	t.Run("starts span with op type", func(t *testing.T) {
   136  		tctx, closer := setup(t)
   137  		defer closer()
   138  
   139  		configureSuccessfulNode(tctx)
   140  		tctx.Node.EXPECT().Params().Return(utils.StaticParams("foo"))
   141  
   142  		mtr := mocktracer.New()
   143  
   144  		sp := mtr.StartSpan("root")
   145  		tctx.QueryCtx.Ctx = opentracing.ContextWithSpan(context.Background(), sp)
   146  
   147  		require.NoError(t, doCall(tctx))
   148  		sp.Finish()
   149  
   150  		spans := mtr.FinishedSpans()
   151  
   152  		require.Len(t, spans, 2)
   153  		assert.Equal(t, tctx.Node.Params().OpType(), spans[0].OperationName)
   154  	})
   155  }