first simple test

This commit is contained in:
Henry 2021-01-25 16:35:22 +01:00
parent 6b90c96a5d
commit f4dc1b1f42
16 changed files with 474 additions and 218 deletions

9
go.mod
View File

@ -3,8 +3,9 @@ module go.mindeco.de/ssb-rooms
go 1.15
require (
github.com/cryptix/go v1.5.0
github.com/go-kit/kit v0.10.0
github.com/gorilla/websocket v1.4.1
github.com/gorilla/websocket v1.4.2
github.com/keks/nocomment v0.0.0-20181007001506-30c6dcb4a472
github.com/pkg/errors v0.9.1
github.com/stretchr/testify v1.6.1
@ -12,9 +13,9 @@ require (
go.cryptoscope.co/netwrap v0.1.1
go.cryptoscope.co/secretstream v1.2.2
go.mindeco.de/ssb-refs v0.1.1-0.20210108133850-cf1f44fea870
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad // indirect
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d // indirect
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f // indirect
)
// We need our internal/extra25519 since agl pulled his repo recently.

87
handlers/whoami/whoami.go Normal file
View File

@ -0,0 +1,87 @@
// SPDX-License-Identifier: MIT
package whoami
import (
"context"
"fmt"
"net"
"github.com/cryptix/go/logging"
"go.cryptoscope.co/muxrpc/v2"
refs "go.mindeco.de/ssb-refs"
"go.mindeco.de/ssb-rooms/internal/maybemuxrpc"
)
var (
method = muxrpc.Method{"whoami"}
)
func checkAndLog(log logging.Interface, err error) {
if err != nil {
if err := logging.LogPanicWithStack(log, "checkAndLog", err); err != nil {
log.Log("event", "warning", "msg", "faild to write panic file", "err", err)
}
}
}
func New(log logging.Interface, id refs.FeedRef) maybemuxrpc.Plugin {
return plugin{handler{
log: log,
id: id,
}}
}
type plugin struct {
h handler
}
func (plugin) Name() string { return "whoami" }
func (plugin) Method() muxrpc.Method { return method }
func (wami plugin) Handler() muxrpc.Handler { return wami.h }
func (plugin) Authorize(net.Conn) bool { return true }
type handler struct {
log logging.Interface
id refs.FeedRef
}
func (handler) HandleConnect(ctx context.Context, edp muxrpc.Endpoint) {}
func (h handler) HandleCall(ctx context.Context, req *muxrpc.Request, edp muxrpc.Endpoint) {
// TODO: push manifest check into muxrpc
if req.Type == "" {
req.Type = "async"
}
if req.Method.String() != "whoami" {
req.CloseWithError(fmt.Errorf("wrong method"))
return
}
type ret struct {
ID string `json:"id"`
}
err := req.Return(ctx, ret{h.id.Ref()})
checkAndLog(h.log, err)
}
type endpoint struct {
edp muxrpc.Endpoint
}
func (edp endpoint) WhoAmI(ctx context.Context) (refs.FeedRef, error) {
var resp struct {
ID refs.FeedRef `json:"id"`
}
err := edp.edp.Async(ctx, &resp, muxrpc.TypeJSON, method)
if err != nil {
return refs.FeedRef{}, fmt.Errorf("error making async call: %w", err)
}
return resp.ID, nil
}

View File

@ -21,21 +21,21 @@ var SecretPerms = os.FileMode(0600)
// KeyPair contains a seret handshake keypair and the assosicated feed
type KeyPair struct {
Feed *refs.FeedRef
Feed refs.FeedRef
Pair secrethandshake.EdKeyPair
}
// the format of the .ssb/secret file as defined by the js implementations
type ssbSecret struct {
Curve string `json:"curve"`
ID *refs.FeedRef `json:"id"`
Private string `json:"private"`
Public string `json:"public"`
Curve string `json:"curve"`
ID refs.FeedRef `json:"id"`
Private string `json:"private"`
Public string `json:"public"`
}
// IsValidFeedFormat checks if the passed FeedRef is for one of the two supported formats,
// legacy/crapp or GabbyGrove.
func IsValidFeedFormat(r *refs.FeedRef) error {
func IsValidFeedFormat(r refs.FeedRef) error {
if r.Algo != refs.RefAlgoFeedSSB1 && r.Algo != refs.RefAlgoFeedGabby {
return fmt.Errorf("ssb: unsupported feed format:%s", r.Algo)
}
@ -52,7 +52,10 @@ func NewKeyPair(r io.Reader) (*KeyPair, error) {
}
keyPair := KeyPair{
Feed: &refs.FeedRef{ID: kp.Public[:], Algo: refs.RefAlgoFeedSSB1},
Feed: refs.FeedRef{
ID: kp.Public[:],
Algo: refs.RefAlgoFeedSSB1,
},
Pair: *kp,
}
@ -61,7 +64,7 @@ func NewKeyPair(r io.Reader) (*KeyPair, error) {
// SaveKeyPair serializes the passed KeyPair to path.
// It errors if path already exists.
func SaveKeyPair(kp *KeyPair, path string) error {
func SaveKeyPair(kp KeyPair, path string) error {
if err := IsValidFeedFormat(kp.Feed); err != nil {
return err
}
@ -89,7 +92,7 @@ func SaveKeyPair(kp *KeyPair, path string) error {
}
// EncodeKeyPairAsJSON serializes the passed Keypair into the writer w
func EncodeKeyPairAsJSON(kp *KeyPair, w io.Writer) error {
func EncodeKeyPairAsJSON(kp KeyPair, w io.Writer) error {
var sec = ssbSecret{
Curve: "ed25519",
ID: kp.Feed,

View File

@ -14,7 +14,7 @@ import (
func NewRelativeTimeLogger(w io.Writer) log.Logger {
if w == nil {
w = os.Stderr
w = log.NewSyncWriter(os.Stderr)
}
var rtl relTimeLogger

View File

@ -28,7 +28,7 @@ type Network interface {
GetListenAddr() net.Addr
GetAllEndpoints() []EndpointStat
GetEndpointFor(*refs.FeedRef) (muxrpc.Endpoint, bool)
GetEndpointFor(refs.FeedRef) (muxrpc.Endpoint, bool)
GetConnTracker() ConnTracker

View File

@ -151,10 +151,7 @@ func (n *node) GetConnTracker() ConnTracker {
// GetEndpointFor returns a muxrpc endpoint to call the remote identified by the passed feed ref
// retruns false if there is no such connection
// TODO: merge with conntracker
func (n *node) GetEndpointFor(ref *refs.FeedRef) (muxrpc.Endpoint, bool) {
if ref == nil {
return nil, false
}
func (n *node) GetEndpointFor(ref refs.FeedRef) (muxrpc.Endpoint, bool) {
n.remotesLock.Lock()
defer n.remotesLock.Unlock()

View File

@ -24,7 +24,7 @@ func DefaultKeyPair(r Interface) (*keys.KeyPair, error) {
if err != nil {
return nil, fmt.Errorf("repo: no keypair but couldn't create one either: %w", err)
}
if err := keys.SaveKeyPair(keyPair, secPath); err != nil {
if err := keys.SaveKeyPair(*keyPair, secPath); err != nil {
return nil, fmt.Errorf("repo: error saving new identity file: %w", err)
}
log.Printf("saved identity %s to %s", keyPair.Feed.Ref(), secPath)
@ -62,7 +62,7 @@ func newKeyPair(r Interface, name, algo string, seed io.Reader) (*keys.KeyPair,
return nil, fmt.Errorf("repo: no keypair but couldn't create one either: %w", err)
}
keyPair.Feed.Algo = algo
if err := keys.SaveKeyPair(keyPair, secPath); err != nil {
if err := keys.SaveKeyPair(*keyPair, secPath); err != nil {
return nil, fmt.Errorf("repo: error saving new identity file: %w", err)
}
log.Printf("saved identity %s to %s", keyPair.Feed.Ref(), secPath)

View File

@ -1,7 +0,0 @@
package roomsrv
import "fmt"
func (s *Server) init() error {
return fmt.Errorf("TODO:srv:init")
}

111
roomsrv/init_network.go Normal file
View File

@ -0,0 +1,111 @@
package roomsrv
import (
"fmt"
"net"
"sync"
kitlog "github.com/go-kit/kit/log"
"go.cryptoscope.co/muxrpc/v2"
refs "go.mindeco.de/ssb-refs"
"go.mindeco.de/ssb-rooms/handlers/whoami"
"go.mindeco.de/ssb-rooms/internal/maybemuxrpc"
"go.mindeco.de/ssb-rooms/internal/network"
)
func (s *Server) initNetwork() error {
s.authorizer.lst = make(map[string]struct{})
// muxrpc handler creation and authoratization decider
mkHandler := func(conn net.Conn) (muxrpc.Handler, error) {
// bypassing badger-close bug to go through with an accept (or not) before closing the bot
s.closedMu.Lock()
defer s.closedMu.Unlock()
// todo: master authorize()er
remote, err := network.GetFeedRefFromAddr(conn.RemoteAddr())
if err != nil {
return nil, fmt.Errorf("sbot: expected an address containing an shs-bs addr: %w", err)
}
if s.keyPair.Feed.Equal(remote) {
return s.master.MakeHandler(conn)
}
if s.authorizer.Authorize(conn) {
return s.public.MakeHandler(conn)
}
return nil, fmt.Errorf("not authorized")
}
// whoami
whoami := whoami.New(kitlog.With(s.logger, "unit", "whoami"), s.keyPair.Feed)
s.public.Register(whoami)
s.master.Register(whoami)
// s.master.Register(replicate.NewPlug(s.Users))
// tcp+shs
opts := network.Options{
Logger: s.logger,
Dialer: s.dialer,
ListenAddr: s.listenAddr,
KeyPair: s.keyPair,
AppKey: s.appKey[:],
MakeHandler: mkHandler,
ConnTracker: s.networkConnTracker,
BefreCryptoWrappers: s.preSecureWrappers,
AfterSecureWrappers: s.postSecureWrappers,
WebsocketAddr: s.wsAddr,
}
var err error
s.Network, err = network.New(opts)
if err != nil {
return fmt.Errorf("failed to create network node: %w", err)
}
return nil
}
func (srv *Server) Allow(r refs.FeedRef, yes bool) {
if yes {
srv.authorizer.Add(r)
} else {
srv.authorizer.Remove(r)
}
}
type listAuthorizer struct {
mu sync.Mutex
lst map[string]struct{}
}
var _ maybemuxrpc.Authorizer = (*listAuthorizer)(nil)
func (a *listAuthorizer) Add(feed refs.FeedRef) {
a.mu.Lock()
defer a.mu.Unlock()
a.lst[feed.Ref()] = struct{}{}
}
func (a *listAuthorizer) Remove(feed refs.FeedRef) {
a.mu.Lock()
defer a.mu.Unlock()
delete(a.lst, feed.Ref())
}
func (a *listAuthorizer) Authorize(remote net.Conn) bool {
remoteID, err := network.GetFeedRefFromAddr(remote.RemoteAddr())
if err != nil {
return false
}
a.mu.Lock()
defer a.mu.Unlock()
_, has := a.lst[remoteID.Ref()]
return has
}

111
roomsrv/init_unixsock.go Normal file
View File

@ -0,0 +1,111 @@
// SPDX-License-Identifier: MIT
package roomsrv
import (
"fmt"
"net"
"os"
"path/filepath"
kitlog "github.com/go-kit/kit/log"
"github.com/go-kit/kit/log/level"
"go.cryptoscope.co/muxrpc/v2"
"go.mindeco.de/ssb-rooms/internal/netwraputil"
"go.mindeco.de/ssb-rooms/internal/repo"
)
// WithUNIXSocket enables listening for muxrpc connections on a unix socket files ($repo/socket).
// This socket is not encrypted or authenticated since access to it is mediated by filesystem ownership.
func WithUNIXSocket(yes bool) Option {
return func(s *Server) error {
s.loadUnixSock = yes
return nil
}
}
func (s *Server) initUnixSock() error {
// this races because sbot might not be done with init yet
// TODO: refactor network peer code and make unixsock implement that (those will be inited late anyway)
if s.keyPair == nil {
return fmt.Errorf("sbot/unixsock: keypair is nil. please use unixSocket with LateOption")
}
spoofWrapper := netwraputil.SpoofRemoteAddress(s.keyPair.Feed.ID)
r := repo.New(s.repoPath)
sockPath := r.GetPath("socket")
// local clients (not using network package because we don't want conn limiting or advertising)
c, err := net.Dial("unix", sockPath)
if err == nil {
c.Close()
return fmt.Errorf("sbot: repo already in use, socket accepted connection")
}
os.Remove(sockPath)
os.MkdirAll(filepath.Dir(sockPath), 0700)
uxLis, err := net.Listen("unix", sockPath)
if err != nil {
return err
}
s.closers.Add(uxLis)
go func() {
for {
c, err := uxLis.Accept()
if err != nil {
if nerr, ok := err.(*net.OpError); ok {
if nerr.Err.Error() == "use of closed network connection" {
return
}
}
level.Warn(s.logger).Log("event", "unix sock accept failed", "err", err)
continue
}
wc, err := spoofWrapper(c)
if err != nil {
c.Close()
continue
}
for _, w := range s.postSecureWrappers {
var err error
wc, err = w(wc)
if err != nil {
level.Warn(s.logger).Log("err", err)
c.Close()
continue
}
}
go func(conn net.Conn) {
defer conn.Close()
pkr := muxrpc.NewPacker(conn)
h, err := s.master.MakeHandler(conn)
if err != nil {
level.Warn(s.logger).Log("event", "unix sock make handler", "err", err)
return
}
edp := muxrpc.Handle(pkr, h,
muxrpc.WithContext(s.rootCtx),
muxrpc.WithLogger(kitlog.NewNopLogger()),
)
srv := edp.(muxrpc.Server)
if err := srv.Serve(); err != nil {
level.Warn(s.logger).Log("conn", "serve exited", "err", err, "peer", conn.RemoteAddr())
}
edp.Terminate()
}(wc)
}
}()
return nil
}

View File

@ -11,6 +11,7 @@ import (
kitlog "github.com/go-kit/kit/log"
"go.cryptoscope.co/netwrap"
"go.mindeco.de/ssb-rooms/internal/maybemod/keys"
"go.mindeco.de/ssb-rooms/internal/network"
"go.mindeco.de/ssb-rooms/internal/repo"
)
@ -41,7 +42,7 @@ func WithNamedKeyPair(name string) Option {
return func(s *Server) error {
r := repo.New(s.repoPath)
var err error
s.KeyPair, err = repo.LoadKeyPair(r, name)
s.keyPair, err = repo.LoadKeyPair(r, name)
if err != nil {
return fmt.Errorf("loading named key-pair %q failed: %w", name, err)
}
@ -54,7 +55,7 @@ func WithNamedKeyPair(name string) Option {
func WithJSONKeyPair(blob string) Option {
return func(s *Server) error {
var err error
s.KeyPair, err = keys.ParseKeyPair(strings.NewReader(blob))
s.keyPair, err = keys.ParseKeyPair(strings.NewReader(blob))
if err != nil {
return fmt.Errorf("JSON KeyPair decode failed: %w", err)
}
@ -65,7 +66,7 @@ func WithJSONKeyPair(blob string) Option {
// WithKeyPair exepect a initialized ssb.KeyPair. Useful for testing.
func WithKeyPair(kp *keys.KeyPair) Option {
return func(s *Server) error {
s.KeyPair = kp
s.keyPair = kp
return nil
}
}
@ -90,6 +91,23 @@ func WithContext(ctx context.Context) Option {
// TODO: remove all this network stuff and make them options on network
// WithDialer changes the function that is used to dial remote peers.
// This could be a sock5 connection builder to support tor proxying to hidden services.
func WithDialer(dial netwrap.Dialer) Option {
return func(s *Server) error {
s.dialer = dial
return nil
}
}
// WithNetworkConnTracker changes the connection tracker. See network.NewLastWinsTracker and network.NewAcceptAllTracker.
func WithNetworkConnTracker(ct network.ConnTracker) Option {
return func(s *Server) error {
s.networkConnTracker = ct
return nil
}
}
// WithListenAddr changes the muxrpc listener address. By default it listens to ':8008'.
func WithListenAddr(addr string) Option {
return func(s *Server) error {

View File

@ -16,6 +16,7 @@ import (
"github.com/go-kit/kit/log/level"
"go.cryptoscope.co/netwrap"
refs "go.mindeco.de/ssb-refs"
"go.mindeco.de/ssb-rooms/internal/maybemod/keys"
"go.mindeco.de/ssb-rooms/internal/maybemod/multicloser"
"go.mindeco.de/ssb-rooms/internal/maybemuxrpc"
@ -37,10 +38,13 @@ type Server struct {
Network network.Network
appKey []byte
listenAddr net.Addr
wsAddr string
dialer netwrap.Dialer
loadUnixSock bool
repoPath string
KeyPair *keys.KeyPair
keyPair *keys.KeyPair
networkConnTracker network.ConnTracker
preSecureWrappers []netwrap.ConnWrapper
@ -49,7 +53,11 @@ type Server struct {
public maybemuxrpc.PluginManager
master maybemuxrpc.PluginManager
authorizer maybemuxrpc.Authorizer
authorizer listAuthorizer
}
func (s Server) Whoami() refs.FeedRef {
return s.keyPair.Feed
}
func New(opts ...Option) (*Server, error) {
@ -102,18 +110,24 @@ func New(opts ...Option) (*Server, error) {
r := repo.New(s.repoPath)
if s.KeyPair == nil {
if s.keyPair == nil {
var err error
s.KeyPair, err = repo.DefaultKeyPair(r)
s.keyPair, err = repo.DefaultKeyPair(r)
if err != nil {
return nil, fmt.Errorf("sbot: failed to get keypair: %w", err)
}
}
if err := s.init(); err != nil {
if err := s.initNetwork(); err != nil {
return nil, err
}
if s.loadUnixSock {
if err := s.initUnixSock(); err != nil {
return nil, err
}
}
return &s, nil
}

View File

@ -1,105 +0,0 @@
// SPDX-License-Identifier: MIT
package roomsrv
import (
"fmt"
"net"
"os"
"path/filepath"
kitlog "github.com/go-kit/kit/log"
"github.com/go-kit/kit/log/level"
"go.cryptoscope.co/muxrpc/v2"
"go.mindeco.de/ssb-rooms/internal/netwraputil"
"go.mindeco.de/ssb-rooms/internal/repo"
)
// WithUNIXSocket enables listening for muxrpc connections on a unix socket files ($repo/socket).
// This socket is not encrypted or authenticated since access to it is mediated by filesystem ownership.
func WithUNIXSocket() Option {
return func(s *Server) error {
// this races because sbot might not be done with init yet
// TODO: refactor network peer code and make unixsock implement that (those will be inited late anyway)
if s.KeyPair == nil {
return fmt.Errorf("sbot/unixsock: keypair is nil. please use unixSocket with LateOption")
}
spoofWrapper := netwraputil.SpoofRemoteAddress(s.KeyPair.Feed.ID)
r := repo.New(s.repoPath)
sockPath := r.GetPath("socket")
// local clients (not using network package because we don't want conn limiting or advertising)
c, err := net.Dial("unix", sockPath)
if err == nil {
c.Close()
return fmt.Errorf("sbot: repo already in use, socket accepted connection")
}
os.Remove(sockPath)
os.MkdirAll(filepath.Dir(sockPath), 0700)
uxLis, err := net.Listen("unix", sockPath)
if err != nil {
return err
}
s.closers.Add(uxLis)
go func() {
for {
c, err := uxLis.Accept()
if err != nil {
if nerr, ok := err.(*net.OpError); ok {
if nerr.Err.Error() == "use of closed network connection" {
return
}
}
level.Warn(s.logger).Log("event", "unix sock accept failed", "err", err)
continue
}
wc, err := spoofWrapper(c)
if err != nil {
c.Close()
continue
}
for _, w := range s.postSecureWrappers {
var err error
wc, err = w(wc)
if err != nil {
level.Warn(s.logger).Log("err", err)
c.Close()
continue
}
}
go func(conn net.Conn) {
defer conn.Close()
pkr := muxrpc.NewPacker(conn)
h, err := s.master.MakeHandler(conn)
if err != nil {
level.Warn(s.logger).Log("event", "unix sock make handler", "err", err)
return
}
edp := muxrpc.Handle(pkr, h,
muxrpc.WithContext(s.rootCtx),
muxrpc.WithLogger(kitlog.NewNopLogger()),
)
srv := edp.(muxrpc.Server)
if err := srv.Serve(); err != nil {
level.Warn(s.logger).Log("conn", "serve exited", "err", err, "peer", conn.RemoteAddr())
}
edp.Terminate()
}(wc)
}
}()
return nil
}
}

View File

@ -3,107 +3,93 @@ package go_test
import (
"context"
"crypto/rand"
"net"
"os"
"path/filepath"
"testing"
"time"
"github.com/go-kit/kit/log"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.cryptoscope.co/muxrpc/v2/debug"
"go.cryptoscope.co/muxrpc/v2"
"golang.org/x/sync/errgroup"
"go.mindeco.de/ssb-rooms/internal/maybemod/multicloser/testutils"
refs "go.mindeco.de/ssb-refs"
"go.mindeco.de/ssb-rooms/roomsrv"
)
func TestTunnelServerSimple(t *testing.T) {
// defer leakcheck.Check(t)
r := require.New(t)
if testing.Short() {
return
}
ctx, cancel := context.WithCancel(context.TODO())
a := assert.New(t)
// defer leakcheck.Check(t)
testInit(t)
ctx, cancel := context.WithCancel(context.Background())
botgroup, ctx := errgroup.WithContext(ctx)
info := testutils.NewRelativeTimeLogger(nil)
bs := newBotServer(ctx, info)
os.RemoveAll("testrun")
bs := newBotServer(ctx, mainLog)
appKey := make([]byte, 32)
rand.Read(appKey)
hmacKey := make([]byte, 32)
rand.Read(hmacKey)
srvLog := log.With(info, "peer", "srv")
srv, err := roomsrv.New(
netOpts := []roomsrv.Option{
roomsrv.WithAppKey(appKey),
roomsrv.WithContext(ctx),
roomsrv.WithLogger(srvLog),
roomsrv.WithPostSecureConnWrapper(func(conn net.Conn) (net.Conn, error) {
return debug.WrapDump(filepath.Join("testrun", t.Name(), "muxdump"), conn)
}),
roomsrv.WithRepoPath(filepath.Join("testrun", t.Name(), "srv")),
roomsrv.WithListenAddr(":0"),
)
r.NoError(err)
botgroup.Go(bs.Serve(srv))
bobLog := log.With(info, "peer", "bob")
bob, err := roomsrv.New(
roomsrv.WithAppKey(appKey),
roomsrv.WithContext(ctx),
roomsrv.WithLogger(bobLog),
roomsrv.WithRepoPath(filepath.Join("testrun", t.Name(), "bob")),
roomsrv.WithListenAddr(":0"),
)
r.NoError(err)
botgroup.Go(bs.Serve(bob))
// TODO
// srv.Replicate(bob.KeyPair.Id)
// bob.Replicate(srv.KeyPair.Id)
sess := &simpleSession{
ctx: ctx,
srv: srv,
bob: bob,
redial: func(t *testing.T) {
t.Log("noop")
},
}
tests := []struct {
name string
tf func(t *testing.T)
}{
{"empty", sess.simple},
// {"justMe", sess.wantFirst},
// {"eachOne", sess.eachOne},
// {"eachOneConnet", sess.eachOneConnet},
// {"eachOneBothWant", sess.eachOnBothWant},
}
serv := makeNamedTestBot(t, "srv", netOpts)
botgroup.Go(bs.Serve(serv))
// all on a single connection
botA := makeNamedTestBot(t, "B", netOpts)
botgroup.Go(bs.Serve(botA))
botB := makeNamedTestBot(t, "C", netOpts)
botgroup.Go(bs.Serve(botB))
theBots := []*roomsrv.Server{serv, botA, botB}
// only allow B to dial A
serv.Allow(botA.Whoami(), true)
// allow bots to dial the remote
botA.Allow(serv.Whoami(), true)
botB.Allow(serv.Whoami(), true)
// dial up B->A and C->A
// should work (we allowed A)
err := botA.Network.Connect(ctx, serv.Network.GetListenAddr())
r.NoError(err, "connect A to the Server")
// shouldn't work (we did not allowed A)
err = botB.Network.Connect(ctx, serv.Network.GetListenAddr())
r.NoError(err, "connect B to the Server") // we dont see an error because it just establishes the tcp connection
edpOfA, has := botA.Network.GetEndpointFor(serv.Whoami())
r.True(has, "botA has no endpoint for the server")
var srvWho struct {
ID refs.FeedRef
}
err = edpOfA.Async(ctx, &srvWho, muxrpc.TypeJSON, muxrpc.Method{"whoami"})
r.NoError(err)
for _, tc := range tests {
t.Run("noop/"+tc.name, tc.tf)
t.Log("server whoami:", srvWho.ID.Ref())
a.True(serv.Whoami().Equal(&srvWho.ID))
edpOfB, has := botB.Network.GetEndpointFor(serv.Whoami())
r.False(has, "botB has an endpoint for the server!")
if edpOfB != nil {
t.Error("should not have an endpoint on B")
err = edpOfB.Async(ctx, &srvWho, muxrpc.TypeJSON, muxrpc.Method{"whoami"})
r.Error(err)
t.Log(srvWho.ID.Ref())
}
srv.Shutdown()
bob.Shutdown()
// cleanup
cancel()
r.NoError(srv.Close())
r.NoError(bob.Close())
time.Sleep(1 * time.Second)
for _, bot := range theBots {
bot.Shutdown()
r.NoError(bot.Close())
}
r.NoError(botgroup.Wait())
}
type simpleSession struct {
ctx context.Context
redial func(t *testing.T)
srv, bob *roomsrv.Server
}

View File

@ -4,12 +4,36 @@ import (
"context"
"errors"
"io"
"os"
"path/filepath"
"sync"
"testing"
"github.com/go-kit/kit/log"
"github.com/go-kit/kit/log/level"
"github.com/stretchr/testify/require"
"go.mindeco.de/ssb-rooms/internal/maybemod/testutils"
"go.mindeco.de/ssb-rooms/internal/network"
"go.mindeco.de/ssb-rooms/roomsrv"
)
var (
initLogging sync.Once
mainLog = log.NewNopLogger()
)
// cant call testing.pkg in init()
func testInit(t *testing.T) {
initLogging.Do(func() {
if testing.Verbose() {
mainLog = testutils.NewRelativeTimeLogger(nil)
}
})
os.RemoveAll(filepath.Join("testrun", t.Name()))
}
type botServer struct {
ctx context.Context
log log.Logger
@ -31,3 +55,19 @@ func (bs botServer) Serve(s *roomsrv.Server) func() error {
return err
}
}
func makeNamedTestBot(t testing.TB, name string, opts []roomsrv.Option) *roomsrv.Server {
r := require.New(t)
testPath := filepath.Join("testrun", t.Name(), "bot-"+name)
botOptions := append(opts,
roomsrv.WithLogger(log.With(mainLog, "bot", name)),
roomsrv.WithRepoPath(testPath),
roomsrv.WithListenAddr(":0"),
roomsrv.WithNetworkConnTracker(network.NewLastWinsTracker()),
)
theBot, err := roomsrv.New(botOptions...)
r.NoError(err)
return theBot
}