mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 10:54:59 +00:00
273 lines
7.4 KiB
Go
273 lines
7.4 KiB
Go
// Copyright 2022 Molecula Corp. (DBA FeatureBase).
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
// package ctl contains all pilosa subcommands other than 'server'. These are
|
|
// generally administration, testing, and debugging tools.
|
|
|
|
package client
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"reflect"
|
|
"testing"
|
|
|
|
"github.com/molecula/featurebase/v3/pb"
|
|
)
|
|
|
|
func TestNewRowResultFromInternal(t *testing.T) {
|
|
targetColumns := []uint64{5, 10}
|
|
row := &pb.Row{
|
|
Columns: []uint64{5, 10},
|
|
}
|
|
result, err := newRowResultFromInternal(row)
|
|
if err != nil {
|
|
t.Fatalf("Failed with error: %s", err)
|
|
}
|
|
if !reflect.DeepEqual(targetColumns, result.Columns) {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
|
|
func TestNewQueryResponseFromInternal(t *testing.T) {
|
|
targetColumns := []uint64{5, 10}
|
|
targetCountItems := []CountResultItem{
|
|
{ID: 10, Count: 100},
|
|
}
|
|
row := &pb.Row{
|
|
Columns: []uint64{5, 10},
|
|
}
|
|
pairs := []*pb.Pair{
|
|
{ID: 10, Count: 100},
|
|
}
|
|
response := &pb.QueryResponse{
|
|
Results: []*pb.QueryResult{
|
|
{Type: QueryResultTypeRow, Row: row},
|
|
{Type: QueryResultTypePairs, Pairs: pairs},
|
|
},
|
|
Err: "",
|
|
}
|
|
qr, err := newQueryResponseFromInternal(response)
|
|
if err != nil {
|
|
t.Fatalf("Failed with error: %s", err)
|
|
}
|
|
if qr.ErrorMessage != "" {
|
|
t.Fatalf("ErrorMessage should be empty")
|
|
}
|
|
if !qr.Success {
|
|
t.Fatalf("IsSuccess should be true")
|
|
}
|
|
|
|
results := qr.Results()
|
|
if len(results) != 2 {
|
|
t.Fatalf("Number of results should be 2")
|
|
}
|
|
if results[0] != qr.Result() {
|
|
t.Fatalf("Result() should return the first result")
|
|
}
|
|
if !reflect.DeepEqual(targetColumns, results[0].Row().Columns) {
|
|
t.Fatalf("The row result should contain the columns")
|
|
}
|
|
if !reflect.DeepEqual(targetCountItems, results[1].CountItems()) {
|
|
t.Fatalf("The response should include count items")
|
|
}
|
|
}
|
|
|
|
func TestNewQueryResponseWithErrorFromInternal(t *testing.T) {
|
|
response := &pb.QueryResponse{
|
|
Err: "some error",
|
|
}
|
|
qr, err := newQueryResponseFromInternal(response)
|
|
if err != nil {
|
|
t.Fatalf("Failed with error: %s", err)
|
|
}
|
|
if qr.ErrorMessage != "some error" {
|
|
t.Fatalf("The response should include the error message")
|
|
}
|
|
if qr.Success {
|
|
t.Fatalf("IsSuccess should be false")
|
|
}
|
|
if qr.Result() != nil {
|
|
t.Fatalf("If there are no results, Result should return nil")
|
|
}
|
|
}
|
|
|
|
func TestCountResultItemToString(t *testing.T) {
|
|
tests := []struct {
|
|
item *CountResultItem
|
|
expected string
|
|
}{
|
|
{item: &CountResultItem{ID: 100, Count: 50}, expected: "100:50"},
|
|
{item: &CountResultItem{Key: "blah", Count: 50}, expected: "blah:50"},
|
|
{item: &CountResultItem{Key: "blah", ID: 22, Count: 50}, expected: "blah:50"},
|
|
{item: &CountResultItem{Key: "blah", ID: 22}, expected: "blah:0"},
|
|
{item: &CountResultItem{}, expected: "0:0"},
|
|
}
|
|
|
|
for i, tst := range tests {
|
|
t.Run(fmt.Sprintf("%d: ", i), func(t *testing.T) {
|
|
if tst.expected != tst.item.String() {
|
|
t.Fatalf("%s != %s", tst.expected, tst.item.String())
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMarshalResults(t *testing.T) {
|
|
row := &pb.Row{
|
|
Columns: []uint64{5, 10},
|
|
}
|
|
pairs := []*pb.Pair{
|
|
{ID: 10, Count: 100},
|
|
}
|
|
pbufResults := []*pb.QueryResult{
|
|
{Type: QueryResultTypeRow, Row: row},
|
|
{Type: QueryResultTypePairs, Pairs: pairs},
|
|
}
|
|
resultJSONStrings := make([]string, len(pbufResults))
|
|
for i, pr := range pbufResults {
|
|
r, err := newQueryResultFromInternal(pr)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
b, err := json.Marshal(r)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
resultJSONStrings[i] = string(b)
|
|
}
|
|
targetJSON := []string{
|
|
`{"columns":[5,10],"keys":[]}`,
|
|
`[{"id":10,"count":100}]`,
|
|
}
|
|
for i := range targetJSON {
|
|
if sortedString(targetJSON[i]) != sortedString(resultJSONStrings[i]) {
|
|
t.Fatalf("%v != %v ", targetJSON[i], resultJSONStrings[i])
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
func TestUnknownQueryResultType(t *testing.T) {
|
|
result := &pb.QueryResult{
|
|
Type: 999,
|
|
}
|
|
_, err := newQueryResultFromInternal(result)
|
|
if err != ErrUnknownType {
|
|
t.Fatalf("Should have failed with ErrUnknownType")
|
|
}
|
|
}
|
|
|
|
func TestTopNResult(t *testing.T) {
|
|
result := TopNResult{
|
|
CountResultItem{ID: 100, Count: 10},
|
|
}
|
|
expectResult(t, result, QueryResultTypePairsField, RowResult{}, []CountResultItem{{100, "", 10}}, 0, 0, false, nil, RowIdentifiersResult{})
|
|
}
|
|
|
|
func TestRowResult(t *testing.T) {
|
|
result := RowResult{
|
|
Columns: []uint64{1, 2, 3},
|
|
}
|
|
targetBmp := RowResult{
|
|
Columns: []uint64{1, 2, 3},
|
|
}
|
|
expectResult(t, result, QueryResultTypeRow, targetBmp, nil, 0, 0, false, nil, RowIdentifiersResult{})
|
|
}
|
|
|
|
func TestRowResultNilColumns(t *testing.T) {
|
|
result := RowResult{
|
|
Columns: nil,
|
|
}
|
|
_, err := result.MarshalJSON()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestSumCountResult(t *testing.T) {
|
|
result := ValCountResult{
|
|
Val: 100,
|
|
Cnt: 50,
|
|
}
|
|
expectResult(t, result, QueryResultTypeValCount, RowResult{}, nil, 100, 50, false, nil, RowIdentifiersResult{})
|
|
}
|
|
|
|
func TestIntResult(t *testing.T) {
|
|
result := IntResult(11)
|
|
expectResult(t, result, QueryResultTypeUint64, RowResult{}, nil, 0, 11, false, nil, RowIdentifiersResult{})
|
|
}
|
|
|
|
func TestBoolResult(t *testing.T) {
|
|
result := BoolResult(true)
|
|
expectResult(t, result, QueryResultTypeBool, RowResult{}, nil, 0, 0, true, nil, RowIdentifiersResult{})
|
|
}
|
|
|
|
func TestNilResult(t *testing.T) {
|
|
result := NilResult{}
|
|
expectResult(t, result, QueryResultTypeNil, RowResult{}, nil, 0, 0, false, nil, RowIdentifiersResult{})
|
|
}
|
|
|
|
func TestGroupCountResult(t *testing.T) {
|
|
result := GroupCountResult{
|
|
{Groups: []FieldRow{{FieldName: "f1", RowID: 1}}, Count: 2},
|
|
{Groups: []FieldRow{{FieldName: "f1", RowID: 2}}, Count: 1},
|
|
}
|
|
expectResult(t, result, QueryResultTypeGroupCounts, RowResult{}, nil, 0, 0, false, []GroupCount{
|
|
{Groups: []FieldRow{{FieldName: "f1", RowID: 1}}, Count: 2},
|
|
{Groups: []FieldRow{{FieldName: "f1", RowID: 2}}, Count: 1},
|
|
}, RowIdentifiersResult{})
|
|
}
|
|
|
|
func TestGroupCountWithValueResult(t *testing.T) {
|
|
var a, b int64 = -1, 1
|
|
|
|
result := GroupCountResult{
|
|
{Groups: []FieldRow{{FieldName: "f1", Value: &a}}, Count: 1},
|
|
{Groups: []FieldRow{{FieldName: "f1", Value: &b}}, Count: 1},
|
|
}
|
|
|
|
var aa, bb int64 = -1, 1
|
|
expectResult(t, result, QueryResultTypeGroupCounts, RowResult{}, nil, 0, 0, false, []GroupCount{
|
|
{Groups: []FieldRow{{FieldName: "f1", Value: &aa}}, Count: 1},
|
|
{Groups: []FieldRow{{FieldName: "f1", Value: &bb}}, Count: 1},
|
|
}, RowIdentifiersResult{})
|
|
}
|
|
|
|
func TestRowIdentifiersResult(t *testing.T) {
|
|
result := RowIdentifiersResult{
|
|
IDs: []uint64{1, 2, 3, 4},
|
|
}
|
|
expectResult(t, result, QueryResultTypeRowIdentifiers, RowResult{}, nil, 0, 0, false, nil, RowIdentifiersResult{
|
|
IDs: []uint64{1, 2, 3, 4},
|
|
})
|
|
}
|
|
|
|
func expectResult(t *testing.T, r QueryResult, resultType uint32, bmp RowResult,
|
|
countItems []CountResultItem, sum int64, count int64, changed bool,
|
|
groupCounts []GroupCount, rowIdentifiers RowIdentifiersResult) {
|
|
if resultType != r.Type() {
|
|
log.Fatalf("Result type: %d != %d", resultType, r.Type())
|
|
}
|
|
if !reflect.DeepEqual(bmp, r.Row()) {
|
|
log.Fatalf("Row: %v != %v", bmp, r.Row())
|
|
}
|
|
if !reflect.DeepEqual(countItems, r.CountItems()) {
|
|
log.Fatalf("Count items: %v != %v", countItems, r.CountItems())
|
|
}
|
|
if count != r.Count() {
|
|
log.Fatalf("Count: %d != %d", count, r.Count())
|
|
}
|
|
if sum != r.Value() {
|
|
log.Fatalf("Sum: %d != %d", sum, r.Value())
|
|
}
|
|
if changed != r.Changed() {
|
|
log.Fatalf("Changed: %v != %v", changed, r.Changed())
|
|
}
|
|
if !reflect.DeepEqual(groupCounts, r.GroupCounts()) {
|
|
log.Fatalf("Group counts: %v != %v", groupCounts, r.GroupCounts())
|
|
}
|
|
if !reflect.DeepEqual(rowIdentifiers, r.RowIdentifiers()) {
|
|
log.Fatalf("Row identifiers: %v != %v", rowIdentifiers, r.RowIdentifiers())
|
|
}
|
|
}
|