featurebase/holder_internal_test.go
Seebs cf97a0dcb8 overhaul: switch over to using QueryContext
We switch everything to use QueryContext/QueryRead/etc instead
of Qcx/Tx.

We drop the short_txkey subpackage (it's now handled by either
keys or querycontext).

We drop all the dbshard stuff, and all the tx/txfactory stuff.

We remove all the things that related to the old "Block" concept,
which was mostly used by the anti-entropy code, but had one
fragmentary usage left in the ImportRoaringOverwrite case of
ImportRoaring. That's replaced by using a rewriter that deletes
all bits (not just bits in specific columns) from an existing
thing, but writes in new bits. Actually we could probably do that
better with a custom "eradicate-rewriter" that doesn't try to
be clever, and just eliminates things.

This includes a number of minor bug fixes that were
exposed by getting the testing to work. For example:
* When checking whether an operation "requires write", we
  now consider a Delete a kind of a Write, because it is.
* Several tests were relying on the fact that writes through
  Qcx were being committed whether or not the Qcx was ever
  told to finish. With QueryContext, you actually have to
  reach a Commit() or the writes don't happen (except for
  special cases in Delete).
* Replaced a lot of panics with t.Fatalf in tests.

There's also some minor staticcheck fixes, like deleting the
unused "db" member of a boltdb transaction wrapper.
2023-01-11 12:57:56 -06:00

125 lines
3.1 KiB
Go

// Copyright 2021 Molecula Corp. All rights reserved.
package pilosa
import (
"context"
"testing"
qc "github.com/molecula/featurebase/v3/querycontext"
"github.com/stretchr/testify/require"
)
// MustIndexQueryContext gets a query context which can write to
// the specified index (and possibly shards), or fails the test.
// The qcx will be automatically cleaned up when the test completes.
func (h *Holder) MustIndexQueryContext(tb testing.TB, index string, shards ...uint64) qc.QueryContext {
tb.Helper()
// disregard a leading ^0, because that's idiomatic for "all shards"
if len(shards) > 0 && shards[0] == ^uint64(0) {
shards = shards[1:]
}
qcx, err := h.NewIndexQueryContext(context.Background(), index, shards...)
if err != nil {
tb.Fatalf("creating query context: %v", err)
}
tb.Cleanup(qcx.Release)
return qcx
}
// MustQueryContext gets a read-only query context or fails the test.
func (h *Holder) MustQueryContext(tb testing.TB) qc.QueryContext {
tb.Helper()
qcx, err := h.NewQueryContext(context.Background())
if err != nil {
tb.Fatalf("creating query context: %v", err)
}
tb.Cleanup(qcx.Release)
return qcx
}
func setupTest(t *testing.T, h *Holder, rowCol []rowCols, indexName string) (*Index, *Field) {
idx, err := h.CreateIndexIfNotExists(indexName, "", IndexOptions{TrackExistence: true})
if err != nil {
t.Fatalf("failed to create index %v: %v", indexName, err)
}
f, err := idx.CreateFieldIfNotExists("f", "")
if err != nil {
t.Fatalf("failed to create field in index %v: %v", indexName, err)
}
existencefield := idx.existenceFld
qcx := h.MustIndexQueryContext(t, indexName)
for _, r := range rowCol {
_, err = f.SetBit(qcx, r.row, r.col, nil)
if err != nil {
t.Fatalf("failed to set bit in index %v: %v", indexName, err)
}
_, err = existencefield.SetBit(qcx, r.row, r.col, nil)
if err != nil {
t.Fatalf("failed to set bit in index %v: %v", indexName, err)
}
}
require.Nil(t, qcx.Commit())
shardsFound := idx.AvailableShards(includeRemote).Slice()
if len(shardsFound) != 3 {
t.Fatalf("expected 3 shards for index %v, got %v", indexName, len(shardsFound))
}
return idx, f
}
type rowCols struct {
row uint64
col uint64
}
func TestHolder_ProcessDeleteInflight(t *testing.T) {
h := newTestHolder(t)
rowCol := []rowCols{
{1, 1},
{1, 2},
{10, ShardWidth + 1},
{1, ShardWidth * 2},
}
idx1, f1 := setupTest(t, h, rowCol, "idxdelete1")
idx2, f2 := setupTest(t, h, rowCol, "idxdelete2")
err := h.processDeleteInflight()
if err != nil {
t.Fatalf("failed to delete: %v", err)
}
tests := []struct {
idx *Index
f *Field
}{
{idx1, f1},
{idx2, f2},
}
for _, test := range tests {
func() {
idx, f := test.idx, test.f
qcx := h.MustQueryContext(t)
for _, r := range rowCol {
row, err := f.Row(qcx, r.row)
if err != nil {
t.Fatalf("failed to get row: %v", err)
}
existenceRow, err := idx.existenceFld.Row(qcx, r.row)
if err != nil {
t.Fatalf("failed to get row: %v", err)
}
if len(row.Columns()) != 0 || len(existenceRow.Columns()) != 0 {
t.Fatalf("expected columns for fields to be empty after delete")
}
}
}()
}
}