Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: Incorporate gomega matchers #3489

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ require (
github.com/multiformats/go-multibase v0.2.0
github.com/multiformats/go-multicodec v0.9.0
github.com/multiformats/go-multihash v0.2.3
github.com/onsi/gomega v1.36.2
github.com/pelletier/go-toml v1.9.5
github.com/philippgille/chromem-go v0.7.0
github.com/pkg/errors v0.9.1
Expand Down
4 changes: 2 additions & 2 deletions tests/integration/encryption/peer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ func TestDocEncryptionPeer_IfPeerDidNotReceiveKey_ShouldNotFetch(t *testing.T) {
}
}`,
Results: map[string]any{
"Users": testUtils.AnyOf{
"Users": testUtils.AnyOf(
// The key-sync has not yet completed
[]map[string]any{},
// The key-sync has completed
Expand All @@ -149,7 +149,7 @@ func TestDocEncryptionPeer_IfPeerDidNotReceiveKey_ShouldNotFetch(t *testing.T) {
"age": int64(21),
},
},
},
),
},
},
},
Expand Down
15 changes: 11 additions & 4 deletions tests/integration/mutation/create/embeddings/embedding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ package constraints
import (
"testing"

"github.com/onsi/gomega"
"github.com/sourcenetwork/immutable"

testUtils "github.com/sourcenetwork/defradb/tests/integration"
Expand All @@ -23,9 +24,9 @@ func TestMutationCreate_WithMultipleEmbeddingFields_ShouldSucceed(t *testing.T)
Description: "Simple create mutation with multiple embedding fields",
SupportedClientTypes: immutable.Some([]testUtils.ClientType{
// Embedding test with mutations are currently only compatible with the Go client.
// The docID is updated by collection.Create after vector embedding generation and
// The docID is updated by collection. Create after vector embedding generation and
// the HTTP and CLI clients don't receive that updated docID. This causes the waitForUpdateEvents
// to fail sinces it receives an update on a docID that wasn't expected. We will look for a solution
// to fail since it receives an update on a docID that wasn't expected. We will look for a solution
// and update the test accordingly.
testUtils.GoClientType,
}),
Expand Down Expand Up @@ -63,10 +64,16 @@ func TestMutationCreate_WithMultipleEmbeddingFields_ShouldSucceed(t *testing.T)
Results: map[string]any{
"User": []map[string]any{
{
"name_v": testUtils.NewArrayDescription[float32](768),
"name_v": gomega.And(
gomega.BeAssignableToTypeOf([]float32{}),
gomega.HaveLen(768),
),
},
{
"name_v": testUtils.NewArrayDescription[float32](768),
"name_v": gomega.And(
gomega.BeAssignableToTypeOf([]float32{}),
gomega.HaveLen(768),
),
},
},
},
Expand Down
11 changes: 9 additions & 2 deletions tests/integration/mutation/update/embeddings/embedding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ package constraints
import (
"testing"

"github.com/onsi/gomega"
"github.com/sourcenetwork/immutable"

testUtils "github.com/sourcenetwork/defradb/tests/integration"
Expand Down Expand Up @@ -77,10 +78,16 @@ func TestMutationUpdate_WithMultipleEmbeddingFields_ShouldSucceed(t *testing.T)
Results: map[string]any{
"User": []map[string]any{
{
"name_v": testUtils.NewArrayDescription[float32](768),
"name_v": gomega.And(
gomega.BeAssignableToTypeOf([]float32{}),
gomega.HaveLen(768),
),
},
{
"name_v": testUtils.NewArrayDescription[float32](768),
"name_v": gomega.And(
gomega.BeAssignableToTypeOf([]float32{}),
gomega.HaveLen(768),
),
},
},
},
Expand Down
6 changes: 3 additions & 3 deletions tests/integration/net/simple/peer/with_update_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ func TestP2PWithSingleDocumentUpdatePerNode(t *testing.T) {
Results: map[string]any{
"Users": []map[string]any{
{
"Age": testUtils.AnyOf{int64(45), int64(60)},
"Age": testUtils.AnyOf(int64(45), int64(60)),
},
},
},
Expand Down Expand Up @@ -431,7 +431,7 @@ func TestP2PWithMultipleDocumentUpdatesPerNode(t *testing.T) {
Results: map[string]any{
"Users": []map[string]any{
{
"Age": testUtils.AnyOf{int64(47), int64(62)},
"Age": testUtils.AnyOf(int64(47), int64(62)),
},
},
},
Expand Down Expand Up @@ -614,7 +614,7 @@ func TestP2PWithMultipleDocumentUpdatesPerNodeWithP2PCollection(t *testing.T) {
Results: map[string]any{
"Users": []map[string]any{
{
"Age": testUtils.AnyOf{int64(47), int64(62)},
"Age": testUtils.AnyOf(int64(47), int64(62)),
},
{
"Age": int64(60),
Expand Down
126 changes: 90 additions & 36 deletions tests/integration/results.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,49 +13,68 @@ package tests
import (
"encoding/base64"
"encoding/json"
"fmt"
"testing"
"time"

"github.com/ipfs/go-cid"
"github.com/onsi/gomega"
"github.com/onsi/gomega/types"

cid "github.com/ipfs/go-cid"
"github.com/sourcenetwork/immutable"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/sourcenetwork/defradb/client"
)

// Validator instances can be substituted in place of concrete values
// and will be asserted on using their [Validate] function instead of
// asserting direct equality.
//
// They may mutate test state.
//
// Todo: This does not currently support chaining/nesting of Validators,
// although we would like that long term:
// https://github.com/sourcenetwork/defradb/issues/3189
type Validator interface {
Validate(s *state, actualValue any, msgAndArgs ...any)
type stateMatcher struct {
s *state
}

func (matcher *stateMatcher) SetState(s *state) {
matcher.s = s
}

// AnyOf may be used as `Results` field where the value may
// be one of several values, yet the value of that field must be the same
// across all nodes due to strong eventual consistency.
type AnyOf []any
func AnyOf(values ...any) *anyOf {
return &anyOf{
Values: values,
}
}

var _ Validator = (AnyOf)(nil)
type anyOf struct {
stateMatcher
Values []any
}

// Validate asserts that actual result is equal to at least one of the expected results.
//
// The comparison is relaxed when using client types other than goClientType.
func (a AnyOf) Validate(s *state, actualValue any, msgAndArgs ...any) {
switch s.clientType {
type StateMatcher interface {
types.GomegaMatcher
SetState(s *state)
}

var _ StateMatcher = (*anyOf)(nil)

func (matcher *anyOf) Match(actual any) (success bool, err error) {
switch matcher.s.clientType {
case HTTPClientType, CLIClientType:
if !areResultsAnyOf(a, actualValue) {
assert.Contains(s.t, a, actualValue, msgAndArgs...)
if !areResultsAnyOf(matcher.Values, actual) {
return gomega.ContainElement(actual).Match(matcher.Values)
}
default:
assert.Contains(s.t, a, actualValue, msgAndArgs...)
return gomega.ContainElement(actual).Match(matcher.Values)
}
return true, nil
}

func (matcher *anyOf) FailureMessage(actual any) string {
return fmt.Sprintf("Expected\n\t%v\nto be one of\n\t%v", actual, matcher.Values)
}

func (matcher *anyOf) NegatedFailureMessage(actual any) string {
return fmt.Sprintf("Expected\n\t%v\nnot to be one of\n\t%v", actual, matcher.Values)
}

// assertResultsEqual asserts that actual result is equal to the expected result.
Expand All @@ -75,7 +94,7 @@ func assertResultsEqual(t testing.TB, client ClientType, expected any, actual an
// areResultsAnyOf returns true if any of the expected results are of equal value.
//
// Values of type json.Number and immutable.Option will be reduced to their underlying types.
func areResultsAnyOf(expected AnyOf, actual any) bool {
func areResultsAnyOf(expected []any, actual any) bool {
for _, v := range expected {
if areResultsEqual(v, actual) {
return true
Expand All @@ -93,11 +112,18 @@ func areResultsAnyOf(expected AnyOf, actual any) bool {
// It will also ensure that all Cids described by this [UniqueCid] have the same
// valid, Cid value.
type UniqueCid struct {
// ID is the arbitrary, but hopefully descriptive, id of this [UniqueCid].
ID any
stateMatcher
// id is the arbitrary, but hopefully descriptive, id of this [UniqueCid].
id any

valuesMismatch bool
duplicatedID any
castFailed bool
cidDecodeErr error
}

var _ Validator = (*UniqueCid)(nil)
// var _ Validator = (*UniqueCid)(nil)
var _ StateMatcher = (*UniqueCid)(nil)

// NewUniqueCid creates a new [UniqueCid] of the given arbitrary, but hopefully descriptive,
// id.
Expand All @@ -106,34 +132,62 @@ var _ Validator = (*UniqueCid)(nil)
// No other [UniqueCid] ids may describe the same Cid value.
func NewUniqueCid(id any) *UniqueCid {
return &UniqueCid{
ID: id,
id: id,
}
}

func (ucid *UniqueCid) Validate(s *state, actualValue any, msgAndArgs ...any) {
func (matcher *UniqueCid) Match(actual any) (success bool, err error) {
isNew := true
for id, value := range s.cids {
if id == ucid.ID {
require.Equal(s.t, value, actualValue)
for id, value := range matcher.s.cids {
if id == matcher.id {
if value != actual {
matcher.valuesMismatch = true
return false, nil
}
isNew = false
} else {
require.NotEqual(s.t, value, actualValue, "UniqueCid must be unique!", msgAndArgs)
if value == actual {
matcher.duplicatedID = id
return false, nil
}
}
}

if isNew {
value, ok := actualValue.(string)
value, ok := actual.(string)
if !ok {
require.Fail(s.t, "UniqueCid actualValue string cast failed")
matcher.castFailed = true
return false, nil
}

cid, err := cid.Decode(value)
if err != nil {
require.NoError(s.t, err)
matcher.cidDecodeErr = err
return false, nil
}

s.cids[ucid.ID] = cid.String()
matcher.s.cids[matcher.id] = cid.String()
}

return true, nil
}

func (matcher *UniqueCid) FailureMessage(actual any) string {
if matcher.valuesMismatch {
return fmt.Sprintf("Expected Cids with the same id %v to match", matcher.id)
} else if matcher.duplicatedID != nil {
return fmt.Sprintf("Expected Cid value to be unique, but ids \"%v\" and \"%v\" point to the same cid: %v",
matcher.id, matcher.duplicatedID, actual)
} else if matcher.castFailed {
return fmt.Sprintf("Actual value is expected to be convertible to a string. Actual: %v", actual)
} else if matcher.cidDecodeErr != nil {
return fmt.Sprintf("Expected actual value to be a valid Cid. Error: %v", matcher.cidDecodeErr)
}
return ""
}

func (matcher *UniqueCid) NegatedFailureMessage(actual any) string {
panic("UniqueCid cannot be negated")
}

// areResultsEqual returns true if the expected and actual results are of equal value.
Expand Down
26 changes: 0 additions & 26 deletions tests/integration/test_case.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (

"github.com/lens-vm/lens/host-go/config/model"
"github.com/sourcenetwork/immutable"
"github.com/stretchr/testify/require"

"github.com/sourcenetwork/defradb/client"
"github.com/sourcenetwork/defradb/net"
Expand Down Expand Up @@ -814,28 +813,3 @@ type Wait struct {
// Duration is the duration to wait.
Duration time.Duration
}

// ArrayDescription represents an array field.
//
// The test harness will call the Validate method to ensure that the returned array size and type
// match what is described by this struct.
type ArrayDescription[T any] struct {
// Size of the array
Size int
}

// NewArrayDescription creates a new [ArrayDescription] instance allowing validation of the array
// characteristics instead of the content of the array itself.
func NewArrayDescription[T any](size int) ArrayDescription[T] {
return ArrayDescription[T]{
Size: size,
}
}

func (d ArrayDescription[T]) Validate(s *state, actualValue any, msgAndArgs ...any) {
var expT []T
require.IsType(s.t, expT, actualValue, msgAndArgs)
typedActualValue, ok := actualValue.([]T)
require.True(s.t, ok)
require.Equal(s.t, d.Size, len(typedActualValue), msgAndArgs)
}
Loading
Loading