github.com/matrixorigin/matrixone@v0.7.0/pkg/frontend/routine_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 frontend 16 17 import ( 18 "context" 19 "database/sql" 20 "fmt" 21 "github.com/golang/mock/gomock" 22 "github.com/google/uuid" 23 "github.com/matrixorigin/matrixone/pkg/config" 24 mock_frontend "github.com/matrixorigin/matrixone/pkg/frontend/test" 25 "github.com/matrixorigin/matrixone/pkg/logutil" 26 "github.com/matrixorigin/matrixone/pkg/sql/parsers" 27 "github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect" 28 "github.com/matrixorigin/matrixone/pkg/sql/parsers/tree" 29 "github.com/matrixorigin/matrixone/pkg/util/metric" 30 "github.com/matrixorigin/matrixone/pkg/vm/engine" 31 "github.com/matrixorigin/matrixone/pkg/vm/process" 32 "github.com/prashantv/gostub" 33 pcg "github.com/prometheus/client_model/go" 34 "github.com/stretchr/testify/assert" 35 "github.com/stretchr/testify/require" 36 "golang.org/x/sync/errgroup" 37 "sync" 38 "sync/atomic" 39 "testing" 40 "time" 41 ) 42 43 func Test_inc_dec(t *testing.T) { 44 rt := &Routine{} 45 counter := int32(0) 46 eg := errgroup.Group{} 47 48 eg.Go(func() error { 49 rt.increaseCount(func() { 50 atomic.AddInt32(&counter, 1) 51 }) 52 return nil 53 }) 54 time.Sleep(100 * time.Millisecond) 55 56 eg.Go(func() error { 57 rt.decreaseCount(func() { 58 atomic.AddInt32(&counter, -1) 59 }) 60 return nil 61 }) 62 time.Sleep(100 * time.Millisecond) 63 64 err := eg.Wait() 65 assert.NoError(t, err) 66 assert.Equal(t, counter, int32(0)) 67 assert.False(t, rt.connectionBeCounted.Load()) 68 } 69 70 type genMrs func(ses *Session) *MysqlResultSet 71 72 var newMockWrapper = func(ctrl *gomock.Controller, ses *Session, 73 sql2result map[string]genMrs, 74 sql2NoResultSet map[string]bool, sql string, stmt tree.Statement, proc *process.Process) ComputationWrapper { 75 var mrs *MysqlResultSet 76 var columns []interface{} 77 var ok, ok2 bool 78 var err error 79 var gen genMrs 80 if gen, ok = sql2result[sql]; ok { 81 mrs = gen(ses) 82 for _, col := range mrs.Columns { 83 columns = append(columns, col) 84 } 85 } else if _, ok2 = sql2NoResultSet[sql]; ok2 { 86 //no result set 87 } else { 88 panic(fmt.Sprintf("there is no mysqlResultset for the sql %s", sql)) 89 } 90 uuid, _ := uuid.NewUUID() 91 runner := mock_frontend.NewMockComputationRunner(ctrl) 92 runner.EXPECT().Run(gomock.Any()).DoAndReturn(func(uint64) error { 93 proto := ses.GetMysqlProtocol() 94 if mrs != nil { 95 err = proto.SendResultSetTextBatchRowSpeedup(mrs, mrs.GetRowCount()) 96 if err != nil { 97 logutil.Errorf("flush error %v", err) 98 return err 99 } 100 } 101 return nil 102 }).AnyTimes() 103 mcw := mock_frontend.NewMockComputationWrapper(ctrl) 104 mcw.EXPECT().GetAst().Return(stmt).AnyTimes() 105 mcw.EXPECT().GetProcess().Return(proc).AnyTimes() 106 mcw.EXPECT().SetDatabaseName(gomock.Any()).Return(nil).AnyTimes() 107 mcw.EXPECT().GetColumns().Return(columns, nil).AnyTimes() 108 mcw.EXPECT().GetAffectedRows().Return(uint64(0)).AnyTimes() 109 mcw.EXPECT().Compile(gomock.Any(), gomock.Any(), gomock.Any()).Return(runner, nil).AnyTimes() 110 mcw.EXPECT().GetUUID().Return(uuid[:]).AnyTimes() 111 mcw.EXPECT().RecordExecPlan(gomock.Any()).Return(nil).AnyTimes() 112 mcw.EXPECT().GetLoadTag().Return(false).AnyTimes() 113 return mcw 114 } 115 116 func Test_ConnectionCount(t *testing.T) { 117 //client connection method: mysql -h 127.0.0.1 -P 6001 --default-auth=mysql_native_password -uroot -p 118 //client connect 119 //ion method: mysql -h 127.0.0.1 -P 6001 -udump -p 120 ctrl := gomock.NewController(t) 121 defer ctrl.Finish() 122 var conn1, conn2 *sql.DB 123 var err error 124 125 //before anything using the configuration 126 eng := mock_frontend.NewMockEngine(ctrl) 127 eng.EXPECT().New(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() 128 eng.EXPECT().Commit(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() 129 eng.EXPECT().Rollback(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() 130 txnClient := mock_frontend.NewMockTxnClient(ctrl) 131 pu, err := getParameterUnit("test/system_vars_config.toml", eng, txnClient) 132 require.NoError(t, err) 133 134 noResultSet := make(map[string]bool) 135 resultSet := make(map[string]genMrs) 136 137 var wrapperStubFunc = func(db, sql, user string, eng engine.Engine, proc *process.Process, ses *Session) ([]ComputationWrapper, error) { 138 var cw []ComputationWrapper = nil 139 var stmts []tree.Statement = nil 140 var cmdFieldStmt *InternalCmdFieldList 141 var err error 142 if isCmdFieldListSql(sql) { 143 cmdFieldStmt, err = parseCmdFieldList(proc.Ctx, sql) 144 if err != nil { 145 return nil, err 146 } 147 stmts = append(stmts, cmdFieldStmt) 148 } else { 149 stmts, err = parsers.Parse(proc.Ctx, dialect.MYSQL, sql) 150 if err != nil { 151 return nil, err 152 } 153 } 154 155 for _, stmt := range stmts { 156 cw = append(cw, newMockWrapper(ctrl, ses, resultSet, noResultSet, sql, stmt, proc)) 157 } 158 return cw, nil 159 } 160 161 bhStub := gostub.Stub(&GetComputationWrapper, wrapperStubFunc) 162 defer bhStub.Reset() 163 164 ctx := context.WithValue(context.TODO(), config.ParameterUnitKey, pu) 165 rm, _ := NewRoutineManager(ctx, pu) 166 rm.SetSkipCheckUser(true) 167 168 wg := sync.WaitGroup{} 169 wg.Add(1) 170 171 //running server 172 go func() { 173 defer wg.Done() 174 echoServer(rm.Handler, rm, NewSqlCodec()) 175 }() 176 177 cCounter := metric.ConnectionCounter(sysAccountName) 178 cCounter.Set(0) 179 180 time.Sleep(time.Second * 2) 181 conn1, err = openDbConn(t, 6001) 182 require.NoError(t, err) 183 184 time.Sleep(time.Second * 2) 185 conn2, err = openDbConn(t, 6001) 186 require.NoError(t, err) 187 188 time.Sleep(time.Second * 2) 189 190 cc := rm.clientCount() 191 assert.GreaterOrEqual(t, cc, 2) 192 193 x := &pcg.Metric{} 194 err = cCounter.Write(x) 195 assert.NoError(t, err) 196 assert.GreaterOrEqual(t, x.Gauge.GetValue(), float64(2)) 197 198 //close the connection 199 closeDbConn(t, conn1) 200 closeDbConn(t, conn2) 201 202 time.Sleep(time.Second * 2) 203 204 cc = rm.clientCount() 205 assert.GreaterOrEqual(t, cc, 0) 206 207 err = cCounter.Write(x) 208 assert.NoError(t, err) 209 assert.GreaterOrEqual(t, x.Gauge.GetValue(), float64(0)) 210 211 time.Sleep(time.Millisecond * 10) 212 //close server 213 setServer(1) 214 wg.Wait() 215 }