| // 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) |
| } |
| } |
| } |