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 }