blob: 06b54b1a5df14c0c3d49e5821692348f161944ae [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_test
import (
"fmt"
"reflect"
"runtime"
"sync"
"time"
"v.io/v23/context"
"v.io/v23/discovery"
"v.io/v23/security"
idiscovery "v.io/x/ref/lib/discovery"
_ "v.io/x/ref/runtime/factories/generic"
)
func advertise(ctx *context.T, ds discovery.Advertiser, visibility []security.BlessingPattern, services ...*discovery.Service) (func(), error) {
var wg sync.WaitGroup
tr := idiscovery.NewTrigger()
ctx, cancel := context.WithCancel(ctx)
for _, service := range services {
wg.Add(1)
done, err := ds.Advertise(ctx, service, visibility)
if err != nil {
cancel()
return nil, fmt.Errorf("Advertise failed: %v", err)
}
tr.Add(wg.Done, done)
}
stop := func() {
cancel()
wg.Wait()
}
return stop, nil
}
func startScan(ctx *context.T, ds discovery.Scanner, interfaceName string) (<-chan discovery.Update, func(), error) {
var query string
if len(interfaceName) > 0 {
query = `v.InterfaceName="` + interfaceName + `"`
}
ctx, stop := context.WithCancel(ctx)
scan, err := ds.Scan(ctx, query)
if err != nil {
return nil, nil, fmt.Errorf("Scan failed: %v", err)
}
return scan, stop, err
}
func scan(ctx *context.T, ds discovery.Scanner, interfaceName string) ([]discovery.Update, error) {
scan, stop, err := startScan(ctx, ds, interfaceName)
if err != nil {
return nil, err
}
defer stop()
var updates []discovery.Update
for {
select {
case update := <-scan:
updates = append(updates, update)
case <-time.After(5 * time.Millisecond):
return updates, nil
}
}
}
func scanAndMatch(ctx *context.T, ds discovery.Scanner, interfaceName string, wants ...discovery.Service) error {
const timeout = 3 * time.Second
var updates []discovery.Update
for now := time.Now(); time.Since(now) < timeout; {
runtime.Gosched()
var err error
updates, err = scan(ctx, ds, interfaceName)
if err != nil {
return err
}
if matchFound(updates, wants...) {
return nil
}
}
return fmt.Errorf("Match failed; got %v, but wanted %v", updates, wants)
}
func match(updates []discovery.Update, lost bool, wants ...discovery.Service) bool {
for _, want := range wants {
matched := false
for i, update := range updates {
switch u := update.(type) {
case discovery.UpdateFound:
matched = !lost && reflect.DeepEqual(u.Value.Service, want)
case discovery.UpdateLost:
matched = lost && u.Value.InstanceId == want.InstanceId
}
if matched {
updates = append(updates[:i], updates[i+1:]...)
break
}
}
if !matched {
return false
}
}
return len(updates) == 0
}
func matchFound(updates []discovery.Update, wants ...discovery.Service) bool {
return match(updates, false, wants...)
}
func matchLost(updates []discovery.Update, wants ...discovery.Service) bool {
return match(updates, true, wants...)
}