github.com/matrixorigin/matrixone@v0.7.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/process"
    27  	"github.com/stretchr/testify/require"
    28  )
    29  
    30  const (
    31  	Rows          = 10     // default rows
    32  	BenchmarkRows = 100000 // default rows for benchmark
    33  )
    34  
    35  // add unit tests for cases
    36  type groupTestCase struct {
    37  	arg    *Argument
    38  	flgs   []bool // flgs[i] == true: nullable
    39  	types  []types.Type
    40  	proc   *process.Process
    41  	cancel context.CancelFunc
    42  }
    43  
    44  var (
    45  	tcs []groupTestCase
    46  )
    47  
    48  func init() {
    49  	tcs = []groupTestCase{
    50  		newTestCase([]bool{false}, false, []types.Type{{Oid: types.T_int8}}),
    51  		newTestCase([]bool{false}, true, []types.Type{{Oid: types.T_int8}}),
    52  		newTestCase([]bool{false, true}, false, []types.Type{
    53  			{Oid: types.T_int8},
    54  			{Oid: types.T_int16},
    55  		}),
    56  		newTestCase([]bool{false, true}, true, []types.Type{
    57  			{Oid: types.T_int16},
    58  			{Oid: types.T_int64},
    59  		}),
    60  		newTestCase([]bool{false, true}, false, []types.Type{
    61  			{Oid: types.T_int64},
    62  			{Oid: types.T_decimal128},
    63  		}),
    64  		newTestCase([]bool{true, false, true}, false, []types.Type{
    65  			{Oid: types.T_int64},
    66  			{Oid: types.T_int64},
    67  			{Oid: types.T_decimal128},
    68  		}),
    69  		newTestCase([]bool{true, false, true}, false, []types.Type{
    70  			{Oid: types.T_int64},
    71  			{Oid: types.T_varchar, Width: 2},
    72  			{Oid: types.T_decimal128},
    73  		}),
    74  		newTestCase([]bool{true, true, true}, false, []types.Type{
    75  			{Oid: types.T_int64},
    76  			{Oid: types.T_varchar, Width: 2},
    77  			{Oid: types.T_decimal128},
    78  		}),
    79  		newTestCase([]bool{true, true, true}, false, []types.Type{
    80  			{Oid: types.T_int64},
    81  			{Oid: types.T_varchar},
    82  			{Oid: types.T_decimal128},
    83  		}),
    84  		newTestCase([]bool{false, false, false}, false, []types.Type{
    85  			{Oid: types.T_int64},
    86  			{Oid: types.T_varchar},
    87  			{Oid: types.T_decimal128},
    88  		}),
    89  	}
    90  }
    91  
    92  func TestString(t *testing.T) {
    93  	buf := new(bytes.Buffer)
    94  	for _, tc := range tcs {
    95  		String(tc.arg, buf)
    96  	}
    97  }
    98  
    99  func TestGroup(t *testing.T) {
   100  	for _, tc := range tcs {
   101  		err := Prepare(tc.proc, tc.arg)
   102  		require.NoError(t, err)
   103  		tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(t, tc.flgs, tc.types, tc.proc, Rows)
   104  		tc.proc.Reg.MergeReceivers[0].Ch <- &batch.Batch{}
   105  		tc.proc.Reg.MergeReceivers[0].Ch <- nil
   106  		tc.proc.Reg.MergeReceivers[1].Ch <- newBatch(t, tc.flgs, tc.types, tc.proc, Rows)
   107  		tc.proc.Reg.MergeReceivers[1].Ch <- &batch.Batch{}
   108  		tc.proc.Reg.MergeReceivers[1].Ch <- nil
   109  		for {
   110  			if ok, err := Call(0, tc.proc, tc.arg, false, false); ok || err != nil {
   111  				if tc.proc.Reg.InputBatch != nil {
   112  					tc.proc.Reg.InputBatch.Clean(tc.proc.Mp())
   113  				}
   114  				break
   115  			}
   116  		}
   117  		for i := 0; i < len(tc.proc.Reg.MergeReceivers); i++ { // simulating the end of a pipeline
   118  			for len(tc.proc.Reg.MergeReceivers[i].Ch) > 0 {
   119  				bat := <-tc.proc.Reg.MergeReceivers[i].Ch
   120  				if bat != nil {
   121  					bat.Clean(tc.proc.Mp())
   122  				}
   123  			}
   124  		}
   125  		require.Equal(t, int64(0), tc.proc.Mp().CurrNB())
   126  	}
   127  }
   128  
   129  func BenchmarkGroup(b *testing.B) {
   130  	for i := 0; i < b.N; i++ {
   131  		tcs = []groupTestCase{
   132  			newTestCase([]bool{false}, true, []types.Type{{Oid: types.T_int8}}),
   133  			newTestCase([]bool{false}, true, []types.Type{{Oid: types.T_int8}}),
   134  		}
   135  		t := new(testing.T)
   136  		for _, tc := range tcs {
   137  			err := Prepare(tc.proc, tc.arg)
   138  			require.NoError(t, err)
   139  			tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(t, tc.flgs, tc.types, tc.proc, Rows)
   140  			tc.proc.Reg.MergeReceivers[0].Ch <- &batch.Batch{}
   141  			tc.proc.Reg.MergeReceivers[0].Ch <- nil
   142  			tc.proc.Reg.MergeReceivers[1].Ch <- newBatch(t, tc.flgs, tc.types, tc.proc, Rows)
   143  			tc.proc.Reg.MergeReceivers[1].Ch <- &batch.Batch{}
   144  			tc.proc.Reg.MergeReceivers[1].Ch <- nil
   145  			for {
   146  				if ok, err := Call(0, tc.proc, tc.arg, false, false); ok || err != nil {
   147  					if tc.proc.Reg.InputBatch != nil {
   148  						tc.proc.Reg.InputBatch.Clean(tc.proc.Mp())
   149  					}
   150  					break
   151  				}
   152  			}
   153  			for i := 0; i < len(tc.proc.Reg.MergeReceivers); i++ { // simulating the end of a pipeline
   154  				for len(tc.proc.Reg.MergeReceivers[i].Ch) > 0 {
   155  					bat := <-tc.proc.Reg.MergeReceivers[i].Ch
   156  					if bat != nil {
   157  						bat.Clean(tc.proc.Mp())
   158  					}
   159  				}
   160  			}
   161  		}
   162  	}
   163  }
   164  
   165  func newTestCase(flgs []bool, needEval bool, ts []types.Type) groupTestCase {
   166  	proc := testutil.NewProcessWithMPool(mpool.MustNewZero())
   167  	proc.Reg.MergeReceivers = make([]*process.WaitRegister, 2)
   168  	ctx, cancel := context.WithCancel(context.Background())
   169  	proc.Reg.MergeReceivers[0] = &process.WaitRegister{
   170  		Ctx: ctx,
   171  		Ch:  make(chan *batch.Batch, 3),
   172  	}
   173  	proc.Reg.MergeReceivers[1] = &process.WaitRegister{
   174  		Ctx: ctx,
   175  		Ch:  make(chan *batch.Batch, 3),
   176  	}
   177  	return groupTestCase{
   178  		types:  ts,
   179  		flgs:   flgs,
   180  		proc:   proc,
   181  		cancel: cancel,
   182  		arg:    &Argument{NeedEval: needEval},
   183  	}
   184  }
   185  
   186  // create a new block based on the type information, flgs[i] == ture: has null
   187  func newBatch(t *testing.T, flgs []bool, ts []types.Type, proc *process.Process, rows int64) *batch.Batch {
   188  	return testutil.NewBatch(ts, false, int(rows), proc.Mp())
   189  }