You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: gc_test.go
    path of file: ./repos/cockroach/pkg/kv/kvserver/gc
    
    the code of the file until where you have to start completion: // Copyright 2020 The Cockroach Authors.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.

package gc

import (
	"bytes"
	"context"
	"fmt"
	"math"
	"math/rand"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"testing"
	"time"

	"github.com/cockroachdb/cockroach/pkg/keys"
	"github.com/cockroachdb/cockroach/pkg/kv/kvpb"
	"github.com/cockroachdb/cockroach/pkg/kv/kvserver/concurrency/isolation"
	"github.com/cockroachdb/cockroach/pkg/kv/kvserver/concurrency/lock"
	"github.com/cockroachdb/cockroach/pkg/roachpb"
	"github.com/cockroachdb/cockroach/pkg/storage"
	"github.com/cockroachdb/cockroach/pkg/storage/enginepb"
	"github.com/cockroachdb/cockroach/pkg/testutils"
	"github.com/cockroachdb/cockroach/pkg/util/encoding"
	"github.com/cockroachdb/cockroach/pkg/util/hlc"
	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
	"github.com/cockroachdb/cockroach/pkg/util/log"
	"github.com/cockroachdb/cockroach/pkg/util/randutil"
	"github.com/cockroachdb/cockroach/pkg/util/uuid"
	"github.com/cockroachdb/errors"
	"github.com/stretchr/testify/require"
)

func TestCalculateThreshold(t *testing.T) {
	for _, c := range []struct {
		gcTTL time.Duration
		ts    hlc.Timestamp
	}{
		{
			ts:    hlc.Timestamp{WallTime: time.Hour.Nanoseconds(), Logical: 0},
			gcTTL: time.Second,
		},
	} {
		require.Equal(t, c.ts, TimestampForThreshold(CalculateThreshold(c.ts, c.gcTTL), c.gcTTL))
	}
}

type collectingGCer struct {
	keys [][]kvpb.GCRequest_GCKey
}

func (c *collectingGCer) GC(
	_ context.Context,
	keys []kvpb.GCRequest_GCKey,
	_ []kvpb.GCRequest_GCRangeKey,
	_ *kvpb.GCRequest_GCClearRange,
) error {
	c.keys = append(c.keys, keys)
	return nil
}

func TestBatchingInlineGCer(t *testing.T) {
	defer leaktest.AfterTest(t)()

	ctx := context.Background()
	c := &collectingGCer{}
	m := makeBatchingInlineGCer(c, func(err error) { t.Error(err) })
	if m.max == 0 {
		t.Fatal("did not init max")
	}
	m.max = 10 // something reasonable for this unit test

	long := kvpb.GCRequest_GCKey{
		Key: bytes.Repeat([]byte("x"), m.max-1),
	}
	short := kvpb.GCRequest_GCKey{
		Key: roachpb.Key("q"),
	}

	m.FlushingAdd(ctx, long.Key)
	require.Nil(t, c.keys) // no flush

	m.FlushingAdd(ctx, short.Key)
	// Flushed long and short.
	require.Len(t, c.keys, 1)
	require.Len(t, c.keys[0], 2)
	requi
    
func TestGCUseClearRange(t *testing.T) {
	defer leaktest.AfterTest(t)()

	first := keys.SystemSQLCodec.TablePrefix(42)
	// mkKey creates a key in a table from a string value. If key ends with a +
	// then Next() key is returned.
	mkKey := func(key string) roachpb.Key {
		if l := len(key); l > 1 && key[l-1] == '+' {
			return append(first[:len(first):len(first)], key[:l-1]...).Next()
		}
		return append(first[:len(first):len(first)], key...)
	}
	last := first.PrefixEnd()

	mkKeyPair := func(start string, startTs int64, end string) gCR {
		return gCR{
			StartKey:          mkKey(start),
			StartKeyTimestamp: hlc.Timestamp{WallTime: startTs * time.Second.Nanoseconds()},
			EndKey:            mkKey(end),
		}
	}
	mkKeyPairToLast := func(start string, startTs int64) gCR {
		return gCR{
			StartKey:          mkKey(start),
			StartKeyTimestamp: hlc.Timestamp{WallTime: startTs * time.Second.Nanoseconds()},
			EndKey:            last,
		}
	}
	mkRawKeyPair := func(start, end roachpb.Key) gCR {
		return gCR{
			StartKey: start,
			EndKey:   end,
		}
	}
	_, _, _ = mkKeyPair, mkKeyPairToLast, mkRawKeyPair
	clearRangeTestDefaults := func(d testRunData) testRunData {
		if d.deleteRangeThreshold == 0 {
			d.deleteRangeThreshold = 1
		}
		if d.keyBytesThreshold == 0 {
			d.keyBytesThreshold = 1
		}
		return d
	}

	for _, d := range []clearRangeTestData{
		{
			name: "clear multiple keys",
			data: testRunData{
				data: `
   | a  bb ccc  d e
---+---------------
 6 |
>5 |
 4 |    C  .    F
 3 | A     ee
 2 |    dd
 1 |
`,
			},
			clearSpans: []gCR{
				mkKeyPair("bb", 2, "ccc+"),
			},
		},
		{
			name: "clear range limits",
			data: testRunData{
				data: `
   | a  bb ccc  d e
---+---------------
 6 |
>5 |            X
 4 |    C  .    y
 3 | A     ee
 2 |    dd      z
 1 |
`,
				deleteRangeThreshold: 3,
			},
			clearSpans: []gCR{
				mkKeyPair("bb", 2, "d"),
			},
		},
		{
			name: "clear multiple keys till end range",
			data: testRunData{
				data: `
   | a  bb ccc  d e
---+---------------
 6 |
>5 |            .
 4 |    C  .    f
 3 | A     ee
 2 |    dd
 1 |
`,
			},
			clearSpans: []gCR{
				mkKeyPair("bb", 2, "d+"),
			},
		},
		{
			name: "clear multiple keys from start range",
			data: testRunData{
				data: `
   | a  bb ccc  d e
---+---------------
 6 |
>5 |            
 4 | .  .  .    F
 3 | a     ee
 2 |    dd
 1 |
`,
			},
			clearSpans: []gCR{
				mkKeyPair("a", 4, "ccc+"),
			},
		},
		{
			name: "clear range restarts on live data",
			data: testRunData{
				data: `
   | a  bb ccc  d e
---+---------------
 7 |
 6 |            X 
>5 |       .     
 4 |    .  e    
 3 | A          . 
 2 |    dd        .
 1 |       ff   y z
`,
				deleteRangeThreshold: 2,
			},
			clearSpans: []gCR{
				mkKeyPair("d", 3, "e+"),
				mkKeyPair("bb", 4, "ccc+"),
			},
		},
		{
			name: "clear range restart on intents",
			data: testRunData{
				data: `
   | a  bb ccc  d e
---+---------------
 7 |
 6 |            !X 
>5 |       .     
 4 |    .  e    .
 3 | A            .
 2 |    dd        x
 1 |       ff   y
`,
			},
			clearSpans: []gCR{
				mkKeyPair("d", 4, "e+"),
				mkKeyPair("bb", 4, "ccc+"),
			},
		},
		{
			name: "clear range when covered by range tombstone",
			data: testRunData{
				data: `
   | a  bb ccc  d e f
---+------------------
 6 |                Z
>5 |    .----------
 4 |    c  f    . .
 3 | A          h i
 2 | b  dd ggg
 1 |      
`,
			},
			clearSpans: []gCR{
				mkKeyPair("a", 2, "e+"),
			},
		},
		{
			name: "clear range with live data above range tombstone",
			data: testRunData{
				data: `
   | a  bb ccc  d e f
---+------------------
 6 |       E         
>5 |    .-----------
 4 |    c  f    . .
 3 | A          h i
 2 | b  dd ggg
 1 |      
`,
			},
			clearSpans: []gCR{
				mkKeyPair("ccc", 4, "e+"),
				mkKeyPair("a", 2, "bb+"),
			},
		},
		{
			name: "clear full range optimization",
			data: testRunData{
				data: `
   | a  bb ccc  d e f
---+------------------
 6 |           
>5 | .--------------
 4 |    c  f    . .
 3 | a          h i
 2 | b  dd ggg
 1 |      
`,
			},
			clearSpans: []gCR{
				{StartKey: first, EndKey: last},
			},
			clearPoints: [][]clearPointsKey{},
		},
	} {
		t.Run(d.name, func(t *testing.T) {
			runTest(t, clearRangeTestDefaults(d.data), func(t *testing.T, gcer *fakeGCer) {
				require.EqualValues(t, d.clearSpans, gCRS(gcer.gcClearRanges).toTestData(),
					"clear range requests")
				if d.clearPoints != nil {
					require.EqualValues(t, d.clearPoints, gcPointsBatches(gcer.gcPointsBatches).toTestData())
				}
			})
		})
	}
}