blob: 2c646318729a1fa9171ed75cfb04b4beea4e279b [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 internal
import (
"fmt"
"math/rand"
"reflect"
"strconv"
"sync"
"testing"
mojom "mojom/vanadium/discovery"
"v.io/v23/context"
"v.io/v23/discovery"
"v.io/v23/security"
idiscovery "v.io/x/ref/lib/discovery"
dfactory "v.io/x/ref/lib/discovery/factory"
_ "v.io/x/ref/runtime/factories/generic"
vtest "v.io/x/ref/test"
)
type mockDiscovery struct {
mu sync.Mutex
trigger *idiscovery.Trigger
id int64
services map[int64]discovery.Service
// An item will be put in deleteCh when something has been deleted.
deleteCh chan struct{}
}
func (d *mockDiscovery) Advertise(ctx *context.T, s *discovery.Service, perms []security.BlessingPattern) (<-chan struct{}, error) {
if len(s.InstanceId) == 0 {
s.InstanceId = strconv.Itoa(rand.Int())
}
d.mu.Lock()
currId := d.id
d.services[currId] = *s
d.id++
d.mu.Unlock()
done := make(chan struct{})
stop := func() {
d.mu.Lock()
delete(d.services, currId)
d.mu.Unlock()
close(done)
go func() { d.deleteCh <- struct{}{} }()
}
d.trigger.Add(stop, ctx.Done())
return done, nil
}
func (*mockDiscovery) Scan(ctx *context.T, query string) (<-chan discovery.Update, error) {
return nil, nil
}
func (*mockDiscovery) Close() {}
func compare(want discovery.Service, got mojom.Service) error {
mwant := v2mService(want)
if !reflect.DeepEqual(mwant, got) {
return fmt.Errorf("Got %#v want %#v", got, want)
}
return nil
}
func mkMojomService(instanceId, interfaceName string, attrs map[string]string, addrs []string) mojom.Service {
return mojom.Service{
InstanceId: &instanceId,
InterfaceName: interfaceName,
Attrs: &attrs,
Addrs: addrs,
}
}
func TestAdvertising(t *testing.T) {
mock := &mockDiscovery{
trigger: idiscovery.NewTrigger(),
services: map[int64]discovery.Service{},
deleteCh: make(chan struct{}),
}
dfactory.InjectDiscovery(mock)
ctx, shutdown := vtest.V23Init()
defer shutdown()
ds := NewDiscoveryService(ctx)
s1 := mkMojomService("s1", "v.io/discovery", map[string]string{"k1": "v1", "k2": "v2"}, []string{"addr1", "addr2"})
h1, id1, e1, e2 := ds.Advertise(s1, nil)
if e1 != nil || e2 != nil {
t.Fatalf("failed to start service: %v, %v", e1, e2)
}
if got, want := id1, "s1"; got != want {
t.Errorf("got instance id %s, but want %s", got, want)
}
if len(mock.services) != 1 {
t.Errorf("service missing in mock")
}
for _, service := range mock.services {
if err := compare(service, s1); err != nil {
t.Error(err)
}
}
s2 := mkMojomService("", "v.io/naming", map[string]string{"k1": "v1", "k2": "v2"}, []string{"addr3", "addr4"})
_, id2, e1, e2 := ds.Advertise(s2, nil)
if e1 != nil || e2 != nil {
t.Fatalf("failed to start service: %v, %v", e1, e2)
}
if len(id2) == 0 {
t.Error("empty instance id returned")
}
s2.InstanceId = &id2
ds.Stop(h1)
// Wait for the deletion to finish.
<-mock.deleteCh
if len(mock.services) != 1 {
t.Errorf("service should have been removed")
}
for _, service := range mock.services {
if err := compare(service, s2); err != nil {
t.Error(err)
}
}
ds.StopAll()
<-mock.deleteCh
if len(mock.services) != 0 {
t.Errorf("service should have been removed")
}
}