blob: 587b443fa857444a44d54bc42e3fd034d464d004 [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package discovery
import (
"math/rand"
"reflect"
"testing"
"testing/quick"
"v.io/v23/discovery"
)
func TestHashAd(t *testing.T) {
a1 := AdInfo{
Ad: discovery.Advertisement{
Id: discovery.AdId{1, 2, 3},
InterfaceName: "v.io/x",
Addresses: []string{
"/@6@wsh@foo.com:1234@@/x",
},
Attributes: discovery.Attributes{
"k1": "v1",
"k2": "v2",
},
}}
// Shouldn't be changed by hashing.
a2 := a1
hashAd(&a2)
a2.Hash = AdHash{}
if !reflect.DeepEqual(a1, a2) {
t.Errorf("shouldn't be changed by hash: %v, %v", a1, a2)
}
// Should have the same hash for the same advertisements.
hashAd(&a1)
hashAd(&a2)
if a1.Hash != a2.Hash {
t.Errorf("expected same hash, but got different: %v, %v", a1.Hash, a2.Hash)
}
// Should be idempotent.
hashAd(&a2)
if a1.Hash != a2.Hash {
t.Errorf("expected same hash, but got different: %v, %v", a1.Hash, a2.Hash)
}
a2.Ad.Id = discovery.AdId{4, 5, 6}
hashAd(&a2)
if a1.Hash == a2.Hash {
t.Errorf("expected different hashes, but got same: %v, %v", a1.Hash, a2.Hash)
}
// Should distinguish between {"", "x"} and {"x", ""}.
a2 = a1
a2.Ad.Attributes = nil
a2.Ad.Attachments = make(discovery.Attachments)
for k, v := range a1.Ad.Attributes {
a2.Ad.Attachments[k] = []byte(v)
}
hashAd(&a2)
if a1.Hash == a2.Hash {
t.Errorf("expected different hashes, but got same: %v, %v", a1.Hash, a2.Hash)
}
// Shouldn't distinguish map order.
a2 = a1
a2.Ad.Attributes = make(discovery.Attributes)
var keys []string
for k, _ := range a1.Ad.Attributes {
keys = append(keys, k)
}
for i := len(keys) - 1; i >= 0; i-- {
a2.Ad.Attributes[keys[i]] = a1.Ad.Attributes[keys[i]]
}
hashAd(&a2)
if a1.Hash != a2.Hash {
t.Errorf("expected same hash, but got different: %v, %v", a1.Hash, a2.Hash)
}
// Shouldn't distinguish between nil and empty.
a2 = a1
a2.Ad.Attachments = make(discovery.Attachments)
hashAd(&a2)
if a1.Hash != a2.Hash {
t.Errorf("expected same hash, but got different: %v, %v", a1.Hash, a2.Hash)
}
}
func TestHashAdCoverage(t *testing.T) {
rand := rand.New(rand.NewSource(0))
gen := func(v reflect.Value) {
for {
r, ok := quick.Value(v.Type(), rand)
if !ok {
t.Fatalf("failed to populate value for %v", v)
}
switch v.Kind() {
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
if r.Len() == 0 {
continue
}
}
if reflect.DeepEqual(v, r) {
continue
}
v.Set(r)
return
}
}
// Ensure that every single field of advertisement is hashed.
ad := AdInfo{}
hashAd(&ad)
for ty, i := reflect.TypeOf(ad.Ad), 0; i < ty.NumField(); i++ {
oldAd := ad
fieldName := reflect.TypeOf(ad.Ad).Field(i).Name
gen(reflect.ValueOf(&ad.Ad).Elem().FieldByName(fieldName))
hashAd(&ad)
if oldAd.Hash == ad.Hash {
t.Errorf("Ad.%s: expected different hashes, but got same: %v, %v", fieldName, oldAd.Hash, ad.Hash)
}
}
for ty, i := reflect.TypeOf(ad), 0; i < ty.NumField(); i++ {
oldAd := ad
fieldName := reflect.TypeOf(ad).Field(i).Name
switch fieldName {
case "Ad", "Hash", "TimestampNs", "DirAddrs", "Status", "Lost":
continue
}
gen(reflect.ValueOf(&ad).Elem().FieldByName(fieldName))
hashAd(&ad)
if oldAd.Hash == ad.Hash {
t.Errorf("AdInfo.%s: expected different hashes, but got same: %v, %v", fieldName, oldAd.Hash, ad.Hash)
}
}
}