blob: 6873eb20afb4679498c202c4a0845251f38bdd3d [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 (
"fmt"
"io"
"os"
"testing"
"time"
"v.io/v23"
"v.io/v23/context"
"v.io/v23/options"
"v.io/x/ref/services/mounttable/mounttablelib"
"v.io/x/ref/test"
"v.io/x/ref/test/modules"
)
//go:generate v23 test generate
func rootMT(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
ctx, shutdown := v23.Init()
defer shutdown()
lspec := v23.GetListenSpec(ctx)
server, err := v23.NewServer(ctx, options.ServesMountTable(true))
if err != nil {
return fmt.Errorf("root failed: %v", err)
}
mt, err := mounttablelib.NewMountTableDispatcher("")
if err != nil {
return fmt.Errorf("mounttable.NewMountTableDispatcher failed: %s", err)
}
eps, err := server.Listen(lspec)
if err != nil {
return fmt.Errorf("server.Listen failed: %s", err)
}
if err := server.ServeDispatcher("", mt); err != nil {
return fmt.Errorf("root failed: %s", err)
}
fmt.Fprintf(stdout, "PID=%d\n", os.Getpid())
for _, ep := range eps {
fmt.Fprintf(stdout, "MT_NAME=%s\n", ep.Name())
}
modules.WaitForEOF(stdin)
return nil
}
// Starts a mounttable. Returns the name and a stop function.
func startMountTable(t *testing.T, ctx *context.T) (string, func()) {
sh, err := modules.NewShell(ctx, nil, testing.Verbose(), t)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
rootMT, err := sh.Start("rootMT", nil, "--v23.tcp.address=127.0.0.1:0")
if err != nil {
t.Fatalf("failed to start root mount table: %s", err)
}
rootMT.ExpectVar("PID")
rootName := rootMT.ExpectVar("MT_NAME")
return rootName, func() {
if err := sh.Cleanup(nil, nil); err != nil {
t.Fatalf("failed to cleanup shell: %s", rootMT.Error())
}
}
}
// Asserts that the channel contains members with expected names and no others.
func AssertMembersWithNames(channel *channel, expectedNames []string) error {
members, err := channel.getMembers()
if err != nil {
return fmt.Errorf("channel.getMembers() failed: %v", err)
}
if actualLen, expectedLen := len(members), len(expectedNames); actualLen != expectedLen {
return fmt.Errorf("Wrong number of members. Expected %v, actual %v.", expectedLen, actualLen)
}
for _, expectedName := range expectedNames {
found := false
for _, member := range members {
if member.Name == expectedName {
found = true
break
}
}
if !found {
return fmt.Errorf("Expected member with name %v, but did not find one.", expectedName)
}
}
return nil
}
func TestMembers(t *testing.T) {
ctx, shutdown := test.InitForTest()
defer shutdown()
mounttable, stopMountTable := startMountTable(t, ctx)
defer stopMountTable()
proxy := ""
path := "path/to/channel"
// Create a new channel.
channel, err := newChannel(ctx, mounttable, proxy, path)
if err != nil {
t.Fatal("newChannel(%v, %v, %v) failed: %v", ctx, mounttable, proxy, path)
}
// New channel should be empty.
if err := AssertMembersWithNames(channel, []string{}); err != nil {
t.Error(err)
}
// Join the channel.
if err := channel.join(); err != nil {
t.Fatalf("channel.join() failed: %v", err)
}
// Channel should contain only current user.
if err := AssertMembersWithNames(channel, []string{channel.UserName()}); err != nil {
t.Error(err)
}
// Create and join the channel a second time.
channel2, err := newChannel(ctx, mounttable, proxy, path)
if err != nil {
t.Fatal("newChannel(%v, %v, %v) failed: %v", ctx, mounttable, proxy, path)
}
if err := channel2.join(); err != nil {
t.Fatalf("channel2.join() failed: %v", err)
}
// Channel should contain both users.
if err := AssertMembersWithNames(channel, []string{channel.UserName(), channel2.UserName()}); err != nil {
t.Error(err)
}
// Leave first instance of channel.
if err := channel.leave(); err != nil {
t.Fatalf("channel.leave() failed: %v", err)
}
// Channel should contain only second user.
if err := AssertMembersWithNames(channel, []string{channel2.UserName()}); err != nil {
t.Error(err)
}
// Leave second instance of channel.
if err := channel2.leave(); err != nil {
t.Fatalf("channel2.leave() failed: %v", err)
}
// Channel should be empty.
if err := AssertMembersWithNames(channel, []string{}); err != nil {
t.Error(err)
}
}
func TestBroadcastMessage(t *testing.T) {
ctx, shutdown := test.InitForTest()
defer shutdown()
mounttable, stopMountTable := startMountTable(t, ctx)
defer stopMountTable()
proxy := ""
path := "path/to/channel"
channel, err := newChannel(ctx, mounttable, proxy, path)
if err != nil {
t.Fatalf("newChannel(%v, %v, %v) failed: %v", ctx, mounttable, proxy, path, err)
}
defer channel.leave()
if err := channel.join(); err != nil {
t.Fatalf("channel.join() failed: %v", err)
}
message := "Hello Vanadium world!"
go func() {
// Call getMembers(), which will set channel.members, used by
// channel.broadcastMessage().
if _, err := channel.getMembers(); err != nil {
t.Fatalf("channel.getMembers() failed: %v", err)
}
if err := channel.broadcastMessage(message); err != nil {
t.Fatalf("channel.broadcastMessage(%v) failed: %v", message, err)
}
}()
select {
case <-time.After(1 * time.Second):
t.Errorf("Timeout waiting for message to be received.")
case m := <-channel.messages:
if m.Text != message {
t.Errorf("Expected message text to be %v but got %v", message, m.Text)
}
if got, want := m.SenderName, channel.UserName(); got != want {
t.Errorf("Got m.SenderName = %v, want %v", got, want)
}
}
}