featurebase/encoding/proto/proto_test.go
Seebs 610c4ed6cb introduce protobuf types for ingest ops
We add a new protobuf type. Also, protoc changed slightly and remade
some tests, in a way which should have no effects but makes the code
*very* slightly cleaner.

This introduces the first testing code in encoding/proto (whoops)
so that scaffolding is a first draft; if you're looking at this code
and the design is a problem go ahead and fix it.

The purpose of this is to verify that we're actually covering all
the branches in the ingest.ShardedRequest and pb.ShardedIngestRequest
message conversions. (Except the top-level one for a nil request,
which isn't checked by this.)

The coverage report doesn't actually include coverage for the ingest
code, though, so we haven't actually properly tested Compare.
Baby steps!
2021-09-27 12:05:57 -05:00

149 lines
4 KiB
Go

// Copyright 2021 Molecula Corp.
//
// 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,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package proto
import (
"errors"
"reflect"
"testing"
"github.com/molecula/featurebase/v2"
"github.com/molecula/featurebase/v2/ingest"
)
func testOneRoundTrip(t *testing.T, s pilosa.Serializer, obj pilosa.Message, expectedMarshalErr error, expectedUnmarshalErr error, expectedMismatchErr error) {
repr, err := s.Marshal(obj)
if err != nil {
if expectedMarshalErr == nil {
t.Fatalf("unexpected marshalling error %q", err.Error())
}
if err.Error() != expectedMarshalErr.Error() {
t.Fatalf("expecting marshalling error %q, got %q", expectedMarshalErr.Error(), err.Error())
}
} else {
if expectedMarshalErr != nil {
t.Fatalf("expected marshalling error %q, got no error", expectedMarshalErr.Error())
}
}
obj2 := reflect.New(reflect.TypeOf(obj).Elem()).Interface()
err = s.Unmarshal(repr, obj2)
if err != nil {
if expectedUnmarshalErr == nil {
t.Fatalf("unexpected unmarshalling error %q", err.Error())
}
if err.Error() != expectedUnmarshalErr.Error() {
t.Fatalf("expecting unmarshalling error %q, got %q", expectedUnmarshalErr.Error(), err.Error())
}
} else {
if expectedUnmarshalErr != nil {
t.Fatalf("expected unmarshalling error %q, got no error", expectedUnmarshalErr.Error())
}
}
switch real := obj.(type) {
case *ingest.ShardedRequest:
real2 := obj2.(*ingest.ShardedRequest)
err := real.Compare(real2)
if err != nil {
if expectedMismatchErr == nil {
t.Fatalf("unexpected compare error %q", err.Error())
}
if err.Error() != expectedMismatchErr.Error() {
t.Fatalf("expecting compare error %q, got %q", expectedMismatchErr.Error(), err.Error())
}
} else {
if expectedMismatchErr != nil {
t.Fatalf("expected compare error %q, got no error", expectedMismatchErr.Error())
}
}
default:
if !reflect.DeepEqual(obj, obj2) {
t.Fatalf("serialization round trip failed for %T:\nexpected %#v\ngot %#v", obj, obj, obj2)
}
}
}
type shardedIngestRequestTest struct {
req *ingest.ShardedRequest
err error
}
var shardedIngestRequestTestcases = []shardedIngestRequestTest{
{
req: &ingest.ShardedRequest{
Ops: map[uint64][]*ingest.Operation{
1: {
{
OpType: ingest.OpWrite,
ClearFields: []string{"clearField", "clearField2"},
ClearRecordIDs: []uint64{1, 7, 9},
FieldOps: map[string]*ingest.FieldOperation{
"writeAll": {
RecordIDs: []uint64{3, 6, 8},
Values: []uint64{0, 17, 34},
Signed: []int64{-9, 23, 17},
},
"writeValues": {
RecordIDs: []uint64{3, 6, 8},
Values: []uint64{0, 17, 34},
},
"writeSigned": {
RecordIDs: []uint64{3, 6, 8},
Signed: []int64{-9, 23, 17},
},
},
},
{
OpType: ingest.OpSet,
FieldOps: map[string]*ingest.FieldOperation{
"foo": nil,
},
},
},
2: {},
3: nil,
},
},
},
{
req: &ingest.ShardedRequest{
Ops: map[uint64][]*ingest.Operation{
1: {
{
OpType: ingest.OpWrite,
FieldOps: map[string]*ingest.FieldOperation{
"writeAll": {},
},
},
{
OpType: ingest.OpSet,
FieldOps: map[string]*ingest.FieldOperation{
"foo": nil,
},
},
nil,
},
},
},
err: errors.New("shard 1: expected 3 ops, got 2"),
},
}
func TestIngestRoundTrip(t *testing.T) {
for _, tc := range shardedIngestRequestTestcases {
t.Logf("next case")
testOneRoundTrip(t, DefaultSerializer, tc.req, nil, nil, tc.err)
}
}