blob: 2d5d4dc27d40564ff47325f767888ae7104d56f2 [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"
"os"
"testing"
"time"
"v.io/v23"
"v.io/v23/options"
"v.io/x/lib/gosh"
"v.io/x/ref/lib/signals"
"v.io/x/ref/lib/v23test"
"v.io/x/ref/services/mounttable/mounttablelib"
)
// TODO(sadovsky): Switch to using v23test.Shell.StartRootMountTable.
var rootMT = gosh.Register("rootMT", func() error {
ctx, shutdown := v23.Init()
defer shutdown()
mt, err := mounttablelib.NewMountTableDispatcher(ctx, "", "", "mounttable")
if err != nil {
return fmt.Errorf("mounttable.NewMountTableDispatcher failed: %s", err)
}
_, server, err := v23.WithNewDispatchingServer(ctx, "", mt, options.ServesMountTable(true))
if err != nil {
return fmt.Errorf("root failed: %v", err)
}
fmt.Printf("PID=%d\n", os.Getpid())
for _, ep := range server.Status().Endpoints {
fmt.Printf("MT_NAME=%s\n", ep.Name())
}
<-signals.ShutdownOnSignals(ctx)
return nil
})
// Asserts that the channel contains members with expected names and no others.
func AssertMembersWithNames(channel *channel, expectedNames []string, retry bool) error {
waitForN := func(expected int) ([]*member, error) {
deadline := time.Now().Add(5 * time.Minute)
for {
members, err := channel.getMembers()
if err != nil || len(members) != expected {
if retry {
if time.Now().After(deadline) {
return nil, fmt.Errorf("timed out expecting %d members", expected)
}
time.Sleep(10 * time.Millisecond)
continue
}
if err != nil {
return nil, fmt.Errorf("channel.getMembers() failed: %v", err)
}
return nil, fmt.Errorf("Wrong number of members. Expected %v, actual %v.", len(members), expected)
}
return members, nil
}
}
members, err := waitForN(len(expectedNames))
if err != nil {
return err
}
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) {
sh := v23test.NewShell(t, v23test.Opts{})
defer sh.Cleanup()
ctx := sh.Ctx
c := sh.Fn(rootMT)
c.Args = append(c.Args, "--v23.tcp.address=127.0.0.1:0")
c.Start()
c.S.ExpectVar("PID")
mounttable := c.S.ExpectVar("MT_NAME")
proxy := ""
path := "path/to/channel"
// Create a new channel.
channel, err := newChannel(ctx, mounttable, proxy, path)
if err != nil {
t.Fatalf("newChannel(%v, %v, %v) failed: %v", mounttable, proxy, path, err)
}
// New channel should be empty.
if err := AssertMembersWithNames(channel, []string{}, false); 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()}, true); err != nil {
t.Error(err)
}
// Create and join the channel a second time.
channel2, err := newChannel(ctx, mounttable, proxy, path)
if err != nil {
t.Fatalf("newChannel(%v, %v, %v) failed: %v", mounttable, proxy, path, err)
}
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()}, true); 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()}, true); 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{}, true); err != nil {
t.Error(err)
}
}
func TestBroadcastMessage(t *testing.T) {
sh := v23test.NewShell(t, v23test.Opts{})
defer sh.Cleanup()
ctx := sh.Ctx
c := sh.Fn(rootMT)
c.Args = append(c.Args, "--v23.tcp.address=127.0.0.1:0")
c.Start()
c.S.ExpectVar("PID")
mounttable := c.S.ExpectVar("MT_NAME")
proxy := ""
path := "path/to/channel"
channel, err := newChannel(ctx, mounttable, proxy, path)
if err != nil {
t.Fatalf("newChannel(%v, %v, %v) failed: %v", 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().
deadline := time.Now().Add(time.Minute)
for {
m, err := channel.getMembers()
if err != nil {
t.Fatalf("channel.getMembers() failed: %v", err)
}
if len(m) > 0 {
break
}
if time.Now().After(deadline) {
t.Fatalf("channel.getMembers: timed out getting a member")
}
time.Sleep(10 * time.Millisecond)
}
if err := channel.broadcastMessage(message); err != nil {
t.Fatalf("channel.broadcastMessage(%v) failed: %v", message, err)
}
}()
select {
case <-time.After(10 * 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)
}
}
}
func TestMain(m *testing.M) {
os.Exit(v23test.Run(m.Run))
}