blob: 8c33f5aab81fe8f430a5f5c178b9d3cfcba6fe24 [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 main
import (
"bytes"
"encoding/json"
"fmt"
"reflect"
"strings"
"testing"
"unicode"
"unicode/utf8"
"v.io/v23"
"v.io/v23/context"
"v.io/v23/naming"
"v.io/v23/rpc"
"v.io/v23/security/access"
"v.io/v23/services/groups"
"v.io/x/lib/cmdline"
"v.io/x/ref/lib/v23cmd"
"v.io/x/ref/test"
)
var group map[string]struct{}
var buffer bytes.Buffer
type mock struct{}
func (mock) Create(ctx *context.T, call rpc.ServerCall, perms access.Permissions, entries []groups.BlessingPatternChunk) error {
fmt.Fprintf(&buffer, "Create(%v, %v) was called", perms, entries)
group = make(map[string]struct{}, len(entries))
for _, entry := range entries {
group[string(entry)] = struct{}{}
}
return nil
}
func (mock) Delete(ctx *context.T, call rpc.ServerCall, version string) error {
fmt.Fprintf(&buffer, "Delete(%v) was called", version)
group = nil
return nil
}
func (mock) Add(ctx *context.T, call rpc.ServerCall, entry groups.BlessingPatternChunk, version string) error {
fmt.Fprintf(&buffer, "Add(%v, %v) was called", entry, version)
group[string(entry)] = struct{}{}
return nil
}
func (mock) Remove(ctx *context.T, call rpc.ServerCall, entry groups.BlessingPatternChunk, version string) error {
fmt.Fprintf(&buffer, "Remove(%v, %v) was called", entry, version)
delete(group, string(entry))
return nil
}
func (mock) Relate(ctx *context.T, call rpc.ServerCall, blessings map[string]struct{}, hint groups.ApproximationType, version string, visitedGroups map[string]struct{}) (map[string]struct{}, []groups.Approximation, string, error) {
fmt.Fprintf(&buffer, "Relate(%v, %v, %v, %v) was called", blessings, hint, version, visitedGroups)
return nil, nil, "123", nil
}
func (mock) Get(ctx *context.T, call rpc.ServerCall, req groups.GetRequest, version string) (groups.GetResponse, string, error) {
return groups.GetResponse{}, "", nil
}
func (mock) SetPermissions(ctx *context.T, call rpc.ServerCall, perms access.Permissions, version string) error {
return nil
}
func (mock) GetPermissions(ctx *context.T, call rpc.ServerCall) (access.Permissions, string, error) {
return nil, "", nil
}
func capitalize(s string) string {
if s == "" {
return ""
}
rune, size := utf8.DecodeRuneInString(s)
return string(unicode.ToUpper(rune)) + s[size:]
}
func startServer(ctx *context.T, t *testing.T) (rpc.Server, naming.Endpoint) {
unpublished := ""
ctx, s, err := v23.WithNewServer(ctx, unpublished, groups.GroupServer(&mock{}), nil)
if err != nil {
t.Fatalf("NewServer(%v) failed: %v", unpublished, err)
}
return s, s.Status().Endpoints[0]
}
func TestGroupClient(t *testing.T) {
ctx, shutdown := test.V23Init()
defer shutdown()
ctx, cancel := context.WithCancel(ctx)
server, endpoint := startServer(ctx, t)
defer func() {
cancel()
<-server.Closed()
}()
// Test the "create" command.
{
var stdout, stderr bytes.Buffer
env := &cmdline.Env{Stdout: &stdout, Stderr: &stderr}
patterns := []string{"alice", "bob"}
args := append([]string{"create", naming.JoinAddressName(endpoint.String(), "")}, patterns...)
if err := v23cmd.ParseAndRunForTest(cmdRoot, ctx, env, args); err != nil {
t.Fatalf("run failed: %v\n%v", err, stderr.String())
}
if got, want := buffer.String(), fmt.Sprintf("Create(%v, %v) was called", access.Permissions{}, patterns); got != want {
t.Errorf("got %v, want %v", got, want)
}
if got, want := strings.TrimSpace(stdout.String()), ""; got != want {
t.Errorf("got %q, want %q", got, want)
}
if got, want := len(group), 2; got != want {
t.Errorf("got %v, want %v", got, want)
}
buffer.Reset()
}
// Test the "add" command.
{
var stdout, stderr bytes.Buffer
env := &cmdline.Env{Stdout: &stdout, Stderr: &stderr}
pattern, version := "charlie", "123"
args := []string{"add", "-version=" + version, naming.JoinAddressName(endpoint.String(), ""), pattern}
if err := v23cmd.ParseAndRunForTest(cmdRoot, ctx, env, args); err != nil {
t.Fatalf("run failed: %v\n%v", err, stderr.String())
}
if got, want := buffer.String(), fmt.Sprintf("Add(%v, %v) was called", pattern, version); got != want {
t.Errorf("got %v, want %v", got, want)
}
if got, want := strings.TrimSpace(stdout.String()), ""; got != want {
t.Errorf("got %q, want %q", got, want)
}
if got, want := len(group), 3; got != want {
t.Errorf("got %v, want %v", got, want)
}
buffer.Reset()
}
// Test the "remove" command.
{
var stdout, stderr bytes.Buffer
env := &cmdline.Env{Stdout: &stdout, Stderr: &stderr}
pattern, version := "bob", "123"
args := []string{"remove", "-version=" + version, naming.JoinAddressName(endpoint.String(), ""), "bob"}
if err := v23cmd.ParseAndRunForTest(cmdRoot, ctx, env, args); err != nil {
t.Fatalf("run failed: %v\n%v", err, stderr.String())
}
if got, want := buffer.String(), fmt.Sprintf("Remove(%v, %v) was called", pattern, version); got != want {
t.Errorf("got %v, want %v", got, want)
}
if got, want := strings.TrimSpace(stdout.String()), ""; got != want {
t.Errorf("got %q, want %q", got, want)
}
if got, want := len(group), 2; got != want {
t.Errorf("got %v, want %v", got, want)
}
buffer.Reset()
}
// Test the "delete" command.
{
var stdout, stderr bytes.Buffer
env := &cmdline.Env{Stdout: &stdout, Stderr: &stderr}
version := "123"
args := []string{"delete", "-version=" + version, naming.JoinAddressName(endpoint.String(), "")}
if err := v23cmd.ParseAndRunForTest(cmdRoot, ctx, env, args); err != nil {
t.Fatalf("run failed: %v\n%v", err, stderr.String())
}
if got, want := buffer.String(), fmt.Sprintf("Delete(%v) was called", version); got != want {
t.Errorf("got %v, want %v", got, want)
}
if got, want := strings.TrimSpace(stdout.String()), ""; got != want {
t.Errorf("got %q, want %q", got, want)
}
if got, want := len(group), 0; got != want {
t.Errorf("got %v, want %v", got, want)
}
buffer.Reset()
}
// Test the "relate" command.
{
var stdout, stderr bytes.Buffer
env := &cmdline.Env{Stdout: &stdout, Stderr: &stderr}
hint, version := "over", "123"
args := []string{"relate", "-approximation=" + hint, "-version=" + version, naming.JoinAddressName(endpoint.String(), "")}
if err := v23cmd.ParseAndRunForTest(cmdRoot, ctx, env, args); err != nil {
t.Fatalf("run failed: %v\n%v", err, stderr.String())
}
empty := map[string]struct{}{}
if got, want := buffer.String(), fmt.Sprintf("Relate(%v, %v, %v, %v) was called", empty, capitalize(hint), version, empty); got != want {
t.Errorf("got %v, want %v", got, want)
}
var got relateResult
if err := json.Unmarshal(stdout.Bytes(), &got); err != nil {
t.Fatalf("Unmarshal(%v) failed: %v", stdout.Bytes(), err)
}
want := relateResult{
Remainder: nil,
Approximations: nil,
Version: "123",
}
if !reflect.DeepEqual(got, want) {
t.Errorf("got %#v, want %#v", got, want)
}
buffer.Reset()
}
}