// 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, shutdown, err := vine.Init(ctx, "vineserver", security.AllowEveryone(), "client", 0)
	if err != nil {
		t.Fatal(err)
	}
	defer shutdown()
	// 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, shutdown, err := vine.Init(ctx, "vineserver", security.AllowEveryone(), "client", 0)
	if err != nil {
		t.Fatal(err)
	}
	defer shutdown()
	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, shutdown, err := vine.Init(ctx, "advertiser", security.AllowEveryone(), "advertiser", 20*time.Millisecond)
	if err != nil {
		t.Fatal(err)
	}
	defer shutdown()
	dctx, shutdown, err := vine.Init(ctx, "scanner", security.AllowEveryone(), "scanner", 20*time.Millisecond)
	if err != nil {
		t.Fatal(err)
	}
	defer shutdown()
	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
}
