github.com/tsuna/gohbase@v0.0.0-20250731002811-4ffcadfba63e/mockrc_test.go (about) 1 // Copyright (C) 2016 The GoHBase Authors. All rights reserved. 2 // This file is part of GoHBase. 3 // Use of this source code is governed by the Apache License 2.0 4 // that can be found in the COPYING file. 5 6 package gohbase 7 8 import ( 9 "bytes" 10 "context" 11 "fmt" 12 "log/slog" 13 "net" 14 "sync" 15 "sync/atomic" 16 "time" 17 18 "github.com/tsuna/gohbase/compression" 19 "github.com/tsuna/gohbase/hrpc" 20 "github.com/tsuna/gohbase/pb" 21 "github.com/tsuna/gohbase/region" 22 "google.golang.org/protobuf/proto" 23 ) 24 25 type testClient struct { 26 addr string 27 numNSRE int32 28 } 29 30 var nsreRegion = &pb.Result{Cell: []*pb.Cell{ 31 &pb.Cell{ 32 Row: []byte("nsre,,1434573235908.56f833d5569a27c7a43fbf547b4924a4."), 33 Family: []byte("info"), 34 Qualifier: []byte("regioninfo"), 35 Value: []byte("PBUF\b\xc4\xcd\xe9\x99\xe0)\x12\x0f\n\adefault\x12\x04nsre" + 36 "\x1a\x00\"\x00(\x000\x008\x00"), 37 }, 38 &pb.Cell{ 39 Row: []byte("nsre,,1434573235908.56f833d5569a27c7a43fbf547b4924a4."), 40 Family: []byte("info"), 41 Qualifier: []byte("seqnumDuringOpen"), 42 Value: []byte("\x00\x00\x00\x00\x00\x00\x00\x02"), 43 }, 44 &pb.Cell{ 45 Row: []byte("nsre,,1434573235908.56f833d5569a27c7a43fbf547b4924a4."), 46 Family: []byte("info"), 47 Qualifier: []byte("server"), 48 Value: []byte("regionserver:1"), 49 }, 50 &pb.Cell{ 51 Row: []byte("nsre,,1434573235908.56f833d5569a27c7a43fbf547b4924a4."), 52 Family: []byte("info"), 53 Qualifier: []byte("serverstartcode"), 54 Value: []byte("\x00\x00\x01N\x02\x92R\xb1"), 55 }, 56 }} 57 58 // makeRegionResult returns a region that spans the whole table 59 // and uses name of the table as the hostname of the regionserver 60 func makeRegionResult(key []byte) *pb.ScanResponse { 61 s := bytes.SplitN(key, []byte(","), 2) 62 fqtable := s[0] 63 64 row := append(fqtable, []byte(",,1434573235908.56f833d5569a27c7a43fbf547b4924a4.")...) 65 t := bytes.SplitN(fqtable, []byte{':'}, 2) 66 var namespace, table []byte 67 if len(t) == 2 { 68 namespace = t[0] 69 table = t[1] 70 } else { 71 namespace = []byte("default") 72 table = fqtable 73 } 74 regionInfo := &pb.RegionInfo{ 75 RegionId: proto.Uint64(1434573235908), 76 TableName: &pb.TableName{ 77 Namespace: namespace, 78 Qualifier: table, 79 }, 80 Offline: proto.Bool(false), 81 } 82 regionInfoValue, err := proto.Marshal(regionInfo) 83 if err != nil { 84 panic(err) 85 } 86 regionInfoValue = append([]byte("PBUF"), regionInfoValue...) 87 88 return &pb.ScanResponse{Results: []*pb.Result{ 89 &pb.Result{Cell: []*pb.Cell{ 90 &pb.Cell{ 91 Row: row, 92 Family: []byte("info"), 93 Qualifier: []byte("regioninfo"), 94 Value: regionInfoValue, 95 }, 96 &pb.Cell{ 97 Row: row, 98 Family: []byte("info"), 99 Qualifier: []byte("seqnumDuringOpen"), 100 Value: []byte("\x00\x00\x00\x00\x00\x00\x00\x02"), 101 }, 102 &pb.Cell{ 103 Row: row, 104 Family: []byte("info"), 105 Qualifier: []byte("server"), 106 Value: fqtable, 107 }, 108 &pb.Cell{ 109 Row: row, 110 Family: []byte("info"), 111 Qualifier: []byte("serverstartcode"), 112 Value: []byte("\x00\x00\x01N\x02\x92R\xb1"), 113 }, 114 }}}} 115 } 116 117 var metaRow = &pb.Result{Cell: []*pb.Cell{ 118 &pb.Cell{ 119 Row: []byte("test,,1434573235908.56f833d5569a27c7a43fbf547b4924a4."), 120 Family: []byte("info"), 121 Qualifier: []byte("regioninfo"), 122 Value: []byte("PBUF\b\xc4\xcd\xe9\x99\xe0)\x12\x0f\n\adefault\x12\x04test" + 123 "\x1a\x00\"\x00(\x000\x008\x00"), 124 }, 125 &pb.Cell{ 126 Row: []byte("test,,1434573235908.56f833d5569a27c7a43fbf547b4924a4."), 127 Family: []byte("info"), 128 Qualifier: []byte("seqnumDuringOpen"), 129 Value: []byte("\x00\x00\x00\x00\x00\x00\x00\x02"), 130 }, 131 &pb.Cell{ 132 Row: []byte("test,,1434573235908.56f833d5569a27c7a43fbf547b4924a4."), 133 Family: []byte("info"), 134 Qualifier: []byte("server"), 135 Value: []byte("regionserver:2"), 136 }, 137 &pb.Cell{ 138 Row: []byte("test,,1434573235908.56f833d5569a27c7a43fbf547b4924a4."), 139 Family: []byte("info"), 140 Qualifier: []byte("serverstartcode"), 141 Value: []byte("\x00\x00\x01N\x02\x92R\xb1"), 142 }, 143 }} 144 145 var test1SplitA = &pb.Result{Cell: []*pb.Cell{ 146 &pb.Cell{ 147 Row: []byte("test1,,1480547738107.825c5c7e480c76b73d6d2bad5d3f7bb8."), 148 Family: []byte("info"), 149 Qualifier: []byte("regioninfo"), 150 Value: []byte("PBUF\b\xfbÖ\xbc\x8b+\x12\x10\n\adefault\x12\x05" + 151 "test1\x1a\x00\"\x03baz(\x000\x008\x00"), 152 }, 153 &pb.Cell{ 154 Row: []byte("test1,,1480547738107.825c5c7e480c76b73d6d2bad5d3f7bb8."), 155 Family: []byte("info"), 156 Qualifier: []byte("seqnumDuringOpen"), 157 Value: []byte("\x00\x00\x00\x00\x00\x00\x00\v"), 158 }, 159 &pb.Cell{ 160 Row: []byte("test1,,1480547738107.825c5c7e480c76b73d6d2bad5d3f7bb8."), 161 Family: []byte("info"), 162 Qualifier: []byte("server"), 163 Value: []byte("regionserver:1"), 164 }, 165 &pb.Cell{ 166 Row: []byte("test1,,1480547738107.825c5c7e480c76b73d6d2bad5d3f7bb8."), 167 Family: []byte("info"), 168 Qualifier: []byte("serverstartcode"), 169 Value: []byte("\x00\x00\x01X\xb6\x83^3"), 170 }, 171 }} 172 173 var m sync.RWMutex 174 var clients map[string]uint32 175 176 func init() { 177 clients = make(map[string]uint32) 178 } 179 180 func newMockRegionClient(addr string, ctype region.ClientType, queueSize int, 181 flushInterval time.Duration, effectiveUser string, 182 readTimeout time.Duration, codec compression.Codec, 183 dialer func(ctx context.Context, network, addr string) (net.Conn, error), 184 log *slog.Logger) hrpc.RegionClient { 185 m.Lock() 186 clients[addr]++ 187 m.Unlock() 188 return &testClient{addr: addr} 189 } 190 191 func (c *testClient) Dial(ctx context.Context) error { 192 return nil 193 } 194 195 func (c *testClient) Addr() string { 196 return c.addr 197 } 198 199 func (c *testClient) String() string { 200 return fmt.Sprintf("RegionClient{Addr: %s}", c.addr) 201 } 202 203 func (c *testClient) QueueRPC(call hrpc.Call) { 204 // ignore timed out rpcs to mock the region client 205 select { 206 case <-call.Context().Done(): 207 return 208 default: 209 } 210 if !bytes.Equal(call.Table(), []byte("hbase:meta")) { 211 _, ok := call.(*hrpc.Get) 212 if !ok || !bytes.HasSuffix(call.Key(), bytes.Repeat([]byte{0}, 17)) { 213 // not a get and not a region probe 214 // just return as the mock call should just populate the ResultChan in test 215 return 216 } 217 // region probe, fail for the nsre region 3 times to force retry 218 if bytes.Equal(call.Table(), []byte("nsre")) { 219 i := atomic.AddInt32(&c.numNSRE, 1) 220 if i <= 3 { 221 call.ResultChan() <- hrpc.RPCResult{Error: region.NotServingRegionError{}} 222 return 223 } 224 } 225 m.RLock() 226 i := clients[c.addr] 227 m.RUnlock() 228 229 // if we are connected to this client the first time, 230 // pretend it's down to fail the probe and start a reconnect 231 if bytes.Equal(call.Table(), []byte("down")) { 232 if i <= 1 { 233 call.ResultChan() <- hrpc.RPCResult{Error: region.ServerError{}} 234 } else { 235 // otherwise, the region is fine 236 call.ResultChan() <- hrpc.RPCResult{} 237 } 238 return 239 } 240 } 241 if bytes.HasSuffix(call.Key(), bytes.Repeat([]byte{0}, 17)) { 242 // meta region probe, return empty to signify that region is online 243 call.ResultChan() <- hrpc.RPCResult{} 244 } else if bytes.HasPrefix(call.Key(), []byte("test,")) { 245 call.ResultChan() <- hrpc.RPCResult{Msg: &pb.ScanResponse{ 246 Results: []*pb.Result{metaRow}}} 247 } else if bytes.HasPrefix(call.Key(), []byte("test1,,")) { 248 call.ResultChan() <- hrpc.RPCResult{Msg: &pb.ScanResponse{ 249 Results: []*pb.Result{test1SplitA}}} 250 } else if bytes.HasPrefix(call.Key(), []byte("nsre,,")) { 251 call.ResultChan() <- hrpc.RPCResult{Msg: &pb.ScanResponse{ 252 Results: []*pb.Result{nsreRegion}}} 253 } else if bytes.HasPrefix(call.Key(), []byte("tablenotfound,")) { 254 call.ResultChan() <- hrpc.RPCResult{Msg: &pb.ScanResponse{ 255 Results: []*pb.Result{}, 256 MoreResults: proto.Bool(false), 257 }} 258 } else { 259 call.ResultChan() <- hrpc.RPCResult{Msg: makeRegionResult(call.Key())} 260 } 261 } 262 263 func (c *testClient) QueueBatch(ctx context.Context, batch []hrpc.Call) { 264 // do nothing. Let the test fill in result. 265 } 266 267 func (c *testClient) Close() {}