blob: 3d2f6b3a53d1f0c87e096dfed5461dbde951f36e [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 vine_test
import (
"testing"
"time"
"v.io/v23"
"v.io/v23/context"
"v.io/v23/discovery"
"v.io/v23/options"
"v.io/v23/rpc"
"v.io/v23/security"
"v.io/x/ref/lib/discovery/testutil"
_ "v.io/x/ref/runtime/factories/generic"
"v.io/x/ref/runtime/protocols/vine"
"v.io/x/ref/test"
)
func TestOutgoingReachable(t *testing.T) {
ctx, shutdown := test.V23InitWithMounttable()
defer shutdown()
ctx, err := vine.Init(ctx, "vineserver", security.AllowEveryone(), "client", 0)
if err != nil {
t.Fatal(err)
}
// Create reachable and unreachable server, ensure they have corresponding tags set.
ctx, cancel := context.WithCancel(ctx)
rctx := vine.WithLocalTag(ctx, "reachable")
uctx := vine.WithLocalTag(ctx, "unreachable")
_, reachServer, err := v23.WithNewServer(rctx, "reachable", &testService{}, security.AllowEveryone())
if err != nil {
t.Error(err)
}
_, unreachServer, err := v23.WithNewServer(uctx, "unreachable", &testService{}, security.AllowEveryone())
if err != nil {
t.Error(err)
}
defer func() {
cancel()
<-reachServer.Closed()
<-unreachServer.Closed()
}()
// Before we set any connection behaviors, a client should not be able to talk
// to either of the servers.
client := v23.GetClient(ctx)
if err := client.Call(ctx, "reachable", "Foo", nil, nil, options.NoRetry{}); err == nil {
t.Errorf("wanted call to fail")
}
if err := client.Call(ctx, "unreachable", "Foo", nil, nil, options.NoRetry{}); err == nil {
t.Errorf("wanted call to fail")
}
// Now, we set connection behaviors that say that "client" can reach "reachable"
// but cannot reach unreachable.
vineClient := vine.VineClient("vineserver")
if err := vineClient.SetBehaviors(ctx, map[vine.PeerKey]vine.PeerBehavior{
vine.PeerKey{"client", "reachable"}: {Reachable: true},
vine.PeerKey{"client", "unreachable"}: {Reachable: false},
}); err != nil {
t.Error(err)
}
// The call to reachable should succeed since the cached connection still exists.
if err := client.Call(ctx, "reachable", "Foo", nil, nil); err != nil {
t.Error(err)
}
// the call to unreachable should fail, since the cached connection should be closed
// and the new attempt to create a connection fails as well.
if err := client.Call(ctx, "unreachable", "Foo", nil, nil, options.NoRetry{}); err == nil {
t.Errorf("wanted call to fail")
}
// Create new clients to avoid using cached connections.
if ctx, _, err = v23.WithNewClient(ctx); err != nil {
t.Error(err)
}
// Now, a call to reachable should still work even without a cached connection.
if err := client.Call(ctx, "reachable", "Foo", nil, nil); err != nil {
t.Error(err)
}
// Now, we remove the entries from the configuration and nothing should be reachable.
if err := vineClient.SetBehaviors(ctx, nil); err != nil {
t.Error(err)
}
if err := client.Call(ctx, "reachable", "Foo", nil, nil, options.NoRetry{}); err == nil {
t.Errorf("wanted call to fail")
}
if err := client.Call(ctx, "unreachable", "Foo", nil, nil, options.NoRetry{}); err == nil {
t.Errorf("wanted call to fail")
}
}
func TestIncomingReachable(t *testing.T) {
ctx, shutdown := test.V23InitWithMounttable()
defer shutdown()
ctx, err := vine.Init(ctx, "vineserver", security.AllowEveryone(), "client", 0)
if err != nil {
t.Fatal(err)
}
denyCtx := vine.WithLocalTag(ctx, "denyClient")
if denyCtx, _, err = v23.WithNewClient(denyCtx); err != nil {
t.Fatal(err)
}
sctx := vine.WithLocalTag(ctx, "server")
sctx, cancel := context.WithCancel(sctx)
_, server, err := v23.WithNewServer(sctx, "server", &testService{}, security.AllowEveryone())
if err != nil {
t.Error(err)
}
defer func() {
cancel()
<-server.Closed()
}()
// Before setting a policy all calls should fail.
if err := v23.GetClient(ctx).Call(ctx, "server", "Foo", nil, nil, options.NoRetry{}); err == nil {
t.Errorf("wanted call to fail")
}
if err := v23.GetClient(denyCtx).Call(denyCtx, "server", "Foo", nil, nil, options.NoRetry{}); err == nil {
t.Errorf("wanted call to fail")
}
// Set a policy that allows "server" to accept connections from "client" but
// denies all connections from "denyClient".
vineClient := vine.VineClient("vineserver")
if err := vineClient.SetBehaviors(ctx, map[vine.PeerKey]vine.PeerBehavior{
vine.PeerKey{"client", "server"}: {Reachable: true},
vine.PeerKey{"denyClient", "server"}: {Reachable: false},
}); err != nil {
t.Error(err)
}
// Now, the call from client to server should work, since the connection is still cached.
if err := v23.GetClient(ctx).Call(ctx, "server", "Foo", nil, nil); err != nil {
t.Error(err)
}
// but the call from denyclient to server should fail, since the cached connection
// should be closed and the new call should also fail.
if err := v23.GetClient(denyCtx).Call(denyCtx, "server", "Foo", nil, nil, options.NoRetry{}); err == nil {
t.Errorf("wanted call to fail")
}
// Create new clients to avoid using cached connections.
if ctx, _, err = v23.WithNewClient(ctx); err != nil {
t.Error(err)
}
// Now, a call with "client" should still work even without a cached connection.
if err := v23.GetClient(ctx).Call(ctx, "server", "Foo", nil, nil); err != nil {
t.Error(err)
}
// After removing all policies all calls should fail again.
if err := vineClient.SetBehaviors(ctx, nil); err != nil {
t.Error(err)
}
if err := v23.GetClient(ctx).Call(ctx, "server", "Foo", nil, nil, options.NoRetry{}); err == nil {
t.Errorf("wanted call to fail")
}
if err := v23.GetClient(denyCtx).Call(denyCtx, "server", "Foo", nil, nil, options.NoRetry{}); err == nil {
t.Errorf("wanted call to fail")
}
}
func TestDiscovery(t *testing.T) {
ctx, shutdown := test.V23InitWithMounttable()
defer shutdown()
actx, err := vine.Init(ctx, "advertiser", security.AllowEveryone(), "advertiser", 20*time.Millisecond)
if err != nil {
t.Fatal(err)
}
dctx, err := vine.Init(ctx, "scanner", security.AllowEveryone(), "scanner", 20*time.Millisecond)
if err != nil {
t.Fatal(err)
}
a, err := v23.NewDiscovery(actx)
if err != nil {
t.Fatal(err)
}
d, err := v23.NewDiscovery(dctx)
if err != nil {
t.Fatal(err)
}
ad := &discovery.Advertisement{
Id: discovery.AdId{1, 2, 3},
InterfaceName: "v.io/x",
Addresses: []string{"/@6@wsh@v1.com@@/x"},
}
astop, err := testutil.Advertise(actx, a, nil, ad)
if err != nil {
t.Fatal(err)
}
defer astop()
// Before setting any behaviors scanner should not be able to discover advertiser.
if err := testutil.ScanAndMatch(dctx, d, ""); err != nil {
t.Error(err)
}
// Set a policy that says scanner can find advertiser.
vineClient := vine.VineClient("advertiser")
if err := vineClient.SetBehaviors(ctx, map[vine.PeerKey]vine.PeerBehavior{
vine.PeerKey{"advertiser", "scanner"}: {Discoverable: true},
}); err != nil {
t.Error(err)
}
// we should find ad when scanning.
if err := testutil.ScanAndMatch(dctx, d, "", *ad); err != nil {
t.Error(err)
}
// Set a policy that says scanner can't find advertiser anymore.
if err := vineClient.SetBehaviors(ctx, map[vine.PeerKey]vine.PeerBehavior{
vine.PeerKey{"advertiser", "scanner"}: {Discoverable: false},
}); err != nil {
t.Error(err)
}
// nothing should be found when scanning.
if err := testutil.ScanAndMatch(dctx, d, ""); err != nil {
t.Error(err)
}
}
type testService struct{}
func (*testService) Foo(*context.T, rpc.ServerCall) error {
return nil
}