Files
tidb/executor/union_iter_test.go

168 lines
3.6 KiB
Go

// Copyright 2021 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.
package executor_test
import (
. "github.com/pingcap/check"
"github.com/pingcap/tidb/executor"
"github.com/pingcap/tidb/kv"
)
var _ = Suite(&testUnionIterSuit{})
type testUnionIterSuit struct {
}
func (s *testUnionIterSuit) TestUnionIter(c *C) {
// test iter normal cases, snap iter become invalid before dirty iter
snapRecords := []*mockRecord{
r("k01", "v1"),
r("k03", "v3"),
r("k06", "v6"),
r("k10", "v10"),
r("k12", "v12"),
r("k15", "v15"),
r("k16", "v16"),
}
dirtyRecords := []*mockRecord{
r("k03", "x3"),
r("k05", "x5"),
r("k07", "x7"),
r("k08", "x8"),
}
assertUnionIter(c, dirtyRecords, snapRecords, []*mockRecord{
r("k01", "v1"),
r("k03", "x3"),
r("k05", "x5"),
r("k06", "v6"),
r("k07", "x7"),
r("k08", "x8"),
r("k10", "v10"),
r("k12", "v12"),
r("k15", "v15"),
r("k16", "v16"),
})
// test iter normal cases, dirty iter become invalid before snap iter
dirtyRecords = []*mockRecord{
r("k03", "x3"),
r("k05", "x5"),
r("k07", "x7"),
r("k08", "x8"),
r("k17", "x17"),
r("k18", "x18"),
}
assertUnionIter(c, dirtyRecords, snapRecords, []*mockRecord{
r("k01", "v1"),
r("k03", "x3"),
r("k05", "x5"),
r("k06", "v6"),
r("k07", "x7"),
r("k08", "x8"),
r("k10", "v10"),
r("k12", "v12"),
r("k15", "v15"),
r("k16", "v16"),
r("k17", "x17"),
r("k18", "x18"),
})
}
func assertUnionIter(c *C, dirtyRecords, snapRecords, expected []*mockRecord) {
iter, err := executor.NewUnionIter(newMockIter(dirtyRecords), newMockIter(snapRecords), false)
c.Assert(err, IsNil)
assertIter(c, iter, expected)
// assert reverse is true
iter, err = executor.NewUnionIter(newMockIter(reverseRecords(dirtyRecords)), newMockIter(reverseRecords(snapRecords)), true)
c.Assert(err, IsNil)
assertIter(c, iter, reverseRecords(expected))
}
func assertIter(c *C, iter kv.Iterator, expected []*mockRecord) {
records := make([]*mockRecord, 0, len(expected))
for iter.Valid() {
records = append(records, &mockRecord{iter.Key(), iter.Value()})
err := iter.Next()
c.Assert(err, IsNil)
}
c.Assert(len(records), Equals, len(expected))
for idx, record := range records {
c.Assert(record.key, BytesEquals, expected[idx].key)
c.Assert(record.value, BytesEquals, expected[idx].value)
}
}
func reverseRecords(records []*mockRecord) []*mockRecord {
reversed := make([]*mockRecord, 0)
for i := range records {
reversed = append(reversed, records[len(records)-i-1])
}
return reversed
}
type mockRecord struct {
key []byte
value []byte
}
func r(key, value string) *mockRecord {
bKey := []byte(key)
bValue := []byte(value)
if value == "nil" {
bValue = nil
}
return &mockRecord{bKey, bValue}
}
type mockIter struct {
data []*mockRecord
cur int
}
func newMockIter(records []*mockRecord) *mockIter {
return &mockIter{
records,
0,
}
}
func (m *mockIter) Valid() bool {
return m.cur >= 0 && m.cur < len(m.data)
}
func (m *mockIter) Key() kv.Key {
return m.data[m.cur].key
}
func (m *mockIter) Value() []byte {
return m.data[m.cur].value
}
func (m *mockIter) Next() error {
if m.Valid() {
m.cur += 1
}
return nil
}
func (m *mockIter) Close() {
m.cur = -1
}