github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/colexec/mergegroup/group_test.go (about)

     1  // Copyright 2021 Matrix Origin
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package mergegroup
    16  
    17  import (
    18  	"bytes"
    19  	"context"
    20  	"testing"
    21  
    22  	"github.com/matrixorigin/matrixone/pkg/common/mpool"
    23  	"github.com/matrixorigin/matrixone/pkg/container/batch"
    24  	"github.com/matrixorigin/matrixone/pkg/container/types"
    25  	"github.com/matrixorigin/matrixone/pkg/testutil"
    26  	"github.com/matrixorigin/matrixone/pkg/vm"
    27  	"github.com/matrixorigin/matrixone/pkg/vm/process"
    28  	"github.com/stretchr/testify/require"
    29  )
    30  
    31  const (
    32  	Rows          = 10     // default rows
    33  	BenchmarkRows = 100000 // default rows for benchmark
    34  )
    35  
    36  // add unit tests for cases
    37  
    38  type groupTestCase struct {
    39  	arg    *Argument
    40  	flgs   []bool // flgs[i] == true: nullable
    41  	types  []types.Type
    42  	proc   *process.Process
    43  	cancel context.CancelFunc
    44  }
    45  
    46  var (
    47  	tcs []groupTestCase
    48  )
    49  
    50  func init() {
    51  	tcs = []groupTestCase{
    52  		newTestCase([]bool{false}, false, []types.Type{types.T_int8.ToType()}),
    53  		newTestCase([]bool{false}, true, []types.Type{types.T_int8.ToType()}),
    54  		newTestCase([]bool{false, true}, false, []types.Type{
    55  			types.T_int8.ToType(),
    56  			types.T_int16.ToType(),
    57  		}),
    58  		newTestCase([]bool{false, true}, true, []types.Type{
    59  			types.T_int16.ToType(),
    60  			types.T_int64.ToType(),
    61  		}),
    62  		newTestCase([]bool{false, true}, false, []types.Type{
    63  			types.T_int64.ToType(),
    64  			types.T_decimal128.ToType(),
    65  		}),
    66  		newTestCase([]bool{true, false, true}, false, []types.Type{
    67  			types.T_int64.ToType(),
    68  			types.T_int64.ToType(),
    69  			types.T_decimal128.ToType(),
    70  		}),
    71  		newTestCase([]bool{true, false, true}, false, []types.Type{
    72  			types.T_int64.ToType(),
    73  			types.New(types.T_varchar, 2, 0),
    74  			types.T_decimal128.ToType(),
    75  		}),
    76  		newTestCase([]bool{true, true, true}, false, []types.Type{
    77  			types.T_int64.ToType(),
    78  			types.New(types.T_varchar, 2, 0),
    79  			types.T_decimal128.ToType(),
    80  		}),
    81  		newTestCase([]bool{true, true, true}, false, []types.Type{
    82  			types.T_int64.ToType(),
    83  			types.T_varchar.ToType(),
    84  			types.T_decimal128.ToType(),
    85  		}),
    86  		newTestCase([]bool{false, false, false}, false, []types.Type{
    87  			types.T_int64.ToType(),
    88  			types.T_varchar.ToType(),
    89  			types.T_decimal128.ToType(),
    90  		}),
    91  	}
    92  }
    93  
    94  func TestString(t *testing.T) {
    95  	buf := new(bytes.Buffer)
    96  	for _, tc := range tcs {
    97  		tc.arg.String(buf)
    98  	}
    99  }
   100  
   101  func TestGroup(t *testing.T) {
   102  	for _, tc := range tcs {
   103  		err := tc.arg.Prepare(tc.proc)
   104  		require.NoError(t, err)
   105  		tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows)
   106  		tc.proc.Reg.MergeReceivers[0].Ch <- batch.EmptyBatch
   107  		tc.proc.Reg.MergeReceivers[0].Ch <- nil
   108  		tc.proc.Reg.MergeReceivers[1].Ch <- newBatch(tc.types, tc.proc, Rows)
   109  		tc.proc.Reg.MergeReceivers[1].Ch <- batch.EmptyBatch
   110  		tc.proc.Reg.MergeReceivers[1].Ch <- nil
   111  		for {
   112  			ok, err := tc.arg.Call(tc.proc)
   113  			if ok.Status == vm.ExecStop || err != nil {
   114  				cleanResult(&ok, tc.proc)
   115  				break
   116  			}
   117  			cleanResult(&ok, tc.proc)
   118  		}
   119  		for i := 0; i < len(tc.proc.Reg.MergeReceivers); i++ { // simulating the end of a pipeline
   120  			for len(tc.proc.Reg.MergeReceivers[i].Ch) > 0 {
   121  				bat := <-tc.proc.Reg.MergeReceivers[i].Ch
   122  				if bat != nil {
   123  					bat.Clean(tc.proc.Mp())
   124  				}
   125  			}
   126  		}
   127  		tc.proc.FreeVectors()
   128  		tc.arg.Free(tc.proc, false, nil)
   129  		require.Equal(t, int64(0), tc.proc.Mp().CurrNB())
   130  	}
   131  }
   132  
   133  func BenchmarkGroup(b *testing.B) {
   134  	for i := 0; i < b.N; i++ {
   135  		tcs = []groupTestCase{
   136  			newTestCase([]bool{false}, true, []types.Type{types.T_int8.ToType()}),
   137  			newTestCase([]bool{false}, true, []types.Type{types.T_int8.ToType()}),
   138  		}
   139  		t := new(testing.T)
   140  		for _, tc := range tcs {
   141  			err := tc.arg.Prepare(tc.proc)
   142  			require.NoError(t, err)
   143  			tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows)
   144  			tc.proc.Reg.MergeReceivers[0].Ch <- batch.EmptyBatch
   145  			tc.proc.Reg.MergeReceivers[0].Ch <- nil
   146  			tc.proc.Reg.MergeReceivers[1].Ch <- newBatch(tc.types, tc.proc, Rows)
   147  			tc.proc.Reg.MergeReceivers[1].Ch <- batch.EmptyBatch
   148  			tc.proc.Reg.MergeReceivers[1].Ch <- nil
   149  			for {
   150  				ok, err := tc.arg.Call(tc.proc)
   151  				if ok.Status == vm.ExecStop || err != nil {
   152  					break
   153  				}
   154  				cleanResult(&ok, tc.proc)
   155  			}
   156  			for i := 0; i < len(tc.proc.Reg.MergeReceivers); i++ { // simulating the end of a pipeline
   157  				for len(tc.proc.Reg.MergeReceivers[i].Ch) > 0 {
   158  					bat := <-tc.proc.Reg.MergeReceivers[i].Ch
   159  					if bat != nil {
   160  						bat.Clean(tc.proc.Mp())
   161  					}
   162  				}
   163  			}
   164  		}
   165  	}
   166  }
   167  
   168  func newTestCase(flgs []bool, needEval bool, ts []types.Type) groupTestCase {
   169  	proc := testutil.NewProcessWithMPool(mpool.MustNewZero())
   170  	proc.Reg.MergeReceivers = make([]*process.WaitRegister, 2)
   171  	ctx, cancel := context.WithCancel(context.Background())
   172  	proc.Reg.MergeReceivers[0] = &process.WaitRegister{
   173  		Ctx: ctx,
   174  		Ch:  make(chan *batch.Batch, 3),
   175  	}
   176  	proc.Reg.MergeReceivers[1] = &process.WaitRegister{
   177  		Ctx: ctx,
   178  		Ch:  make(chan *batch.Batch, 3),
   179  	}
   180  	return groupTestCase{
   181  		types:  ts,
   182  		flgs:   flgs,
   183  		proc:   proc,
   184  		cancel: cancel,
   185  		arg: &Argument{
   186  			NeedEval: needEval,
   187  			OperatorBase: vm.OperatorBase{
   188  				OperatorInfo: vm.OperatorInfo{
   189  					Idx:     0,
   190  					IsFirst: false,
   191  					IsLast:  false,
   192  				},
   193  			},
   194  		},
   195  	}
   196  }
   197  
   198  // create a new block based on the type information, flgs[i] == ture: has null
   199  func newBatch(ts []types.Type, proc *process.Process, rows int64) *batch.Batch {
   200  	return testutil.NewBatch(ts, false, int(rows), proc.Mp())
   201  }
   202  
   203  func cleanResult(result *vm.CallResult, proc *process.Process) {
   204  	if result.Batch != nil {
   205  		result.Batch.Clean(proc.Mp())
   206  	}
   207  }