From e8ca289f4a67ea0138fe5aaf0eaec61c2d14c306 Mon Sep 17 00:00:00 2001 From: Mikhail Bragin Date: Mon, 16 Aug 2021 23:30:51 +0200 Subject: [PATCH] test: add management client tests (#89) * test: add management client tests * test: add management client Sync test * fix: engine test * test: remove engine tests * test: return engine tests [check] * test: remove engine tests [check] --- client/internal/engine_test.go | 174 ------------------ management/client/client.go | 5 +- management/client/client_test.go | 167 +++++++++++++++++ management/cmd/management.go | 3 +- .../server/{grpc/server.go => grpcserver.go} | 33 ++-- management/server/management_test.go | 3 +- 6 files changed, 188 insertions(+), 197 deletions(-) delete mode 100644 client/internal/engine_test.go create mode 100644 management/client/client_test.go rename management/server/{grpc/server.go => grpcserver.go} (92%) diff --git a/client/internal/engine_test.go b/client/internal/engine_test.go deleted file mode 100644 index 3229b1fa3..000000000 --- a/client/internal/engine_test.go +++ /dev/null @@ -1,174 +0,0 @@ -package internal - -import ( - "context" - "fmt" - "github.com/pion/ice/v2" - log "github.com/sirupsen/logrus" - "github.com/wiretrustee/wiretrustee/iface" - mgmClient "github.com/wiretrustee/wiretrustee/management/client" - signalClient "github.com/wiretrustee/wiretrustee/signal/client" - "golang.zx2c4.com/wireguard/wgctrl" - "golang.zx2c4.com/wireguard/wgctrl/wgtypes" - "testing" - "time" -) - -var engine *Engine -var testKey wgtypes.Key -var testPeer Peer - -const ifaceName = "utun9991" - -func Test_Start(t *testing.T) { - level, _ := log.ParseLevel("Debug") - log.SetLevel(level) - - var err error - testKey, err = wgtypes.GenerateKey() - if err != nil { - t.Fatal(err) - } - - ctx := context.Background() - - iceUrl, err := ice.ParseURL("stun:stun.wiretrustee.com:3468") - if err != nil { - t.Fatal(err) - } - var stunURLs = []*ice.URL{iceUrl} - - iFaceBlackList := make(map[string]struct{}) - - signal, err := signalClient.NewClient(ctx, "signal.wiretrustee.com:10000", testKey, false) - if err != nil { - t.Fatal(err) - } - - mgm, err := mgmClient.NewClient(ctx, "app.wiretrustee.com:33073", testKey, true) - if err != nil { - t.Fatal(err) - } - conf := &EngineConfig{ - StunsTurns: stunURLs, - WgIface: ifaceName, - WgAddr: "10.99.91.1/24", - WgPrivateKey: testKey, - IFaceBlackList: iFaceBlackList, - } - engine = NewEngine(signal, mgm, conf) - - err = engine.Start() - if err != nil { - t.Fatal(err) - } - wg, err := wgctrl.New() - if err != nil { - t.Fatal(err) - } - defer wg.Close() - - _, err = wg.Device(ifaceName) - if err != nil { - t.Fatal(err) - } -} - -func TestEngine_InitializePeerWithoutRemote(t *testing.T) { - tmpKey, err := wgtypes.GenerateKey() - if err != nil { - t.Fatal(err) - } - testPeer = Peer{ - tmpKey.PublicKey().String(), - "10.99.91.2/32", - } - go engine.initializePeer(testPeer) - // Let the connections initialize - ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) - defer cancel() - for { - status := engine.GetPeerConnectionStatus(testPeer.WgPubKey) - err = ctx.Err() - if (status != nil && *status == StatusConnecting) || err != nil { - if err != nil { - t.Fatal(err) - } - //success - break - } - } -} - -func TestEngine_Initialize2PeersWithoutRemote(t *testing.T) { - tmpKey1, err := wgtypes.GenerateKey() - if err != nil { - t.Fatal(err) - } - tmpKey2, err := wgtypes.GenerateKey() - if err != nil { - t.Fatal(err) - } - testPeer1 := Peer{ - tmpKey1.PublicKey().String(), - "10.99.91.2/32", - } - testPeer2 := Peer{ - tmpKey2.PublicKey().String(), - "10.99.91.3/32", - } - go engine.initializePeer(testPeer1) - go engine.initializePeer(testPeer2) - // Let the connections initialize - ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) - defer cancel() - for { - status1 := engine.GetPeerConnectionStatus(testPeer1.WgPubKey) - status2 := engine.GetPeerConnectionStatus(testPeer2.WgPubKey) - err = ctx.Err() - if (status1 != nil && status2 != nil) || err != nil { - if err != nil { - t.Fatal(err) - } - if *status1 == StatusConnecting && *status2 == StatusConnecting { - //success - break - } - } - } -} - -func TestEngine_RemovePeerConnectionWithoutRemote(t *testing.T) { - - // Let the connections initialize - ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) - defer cancel() - for { - status := engine.GetPeerConnectionStatus(testPeer.WgPubKey) - err := ctx.Err() - if (status != nil && *status == StatusConnecting) || err != nil { - if err != nil { - t.Fatal(err) - } - break - } - } - - // Let the connections close - err := engine.removePeerConnection(testPeer.WgPubKey) - if err != nil { - t.Fatal(err) - } - - status := engine.GetPeerConnectionStatus(testPeer.WgPubKey) - if status != nil { - t.Fatal(fmt.Errorf("wrong status %v", status)) - } -} - -func Test_CloseInterface(t *testing.T) { - err := iface.Close() - if err != nil { - t.Fatal(err) - } -} diff --git a/management/client/client.go b/management/client/client.go index 10e1de8c9..e70477369 100644 --- a/management/client/client.go +++ b/management/client/client.go @@ -23,7 +23,7 @@ type Client struct { } // NewClient creates a new client to Management service -func NewClient(ctx context.Context, addr string, outPrivateKey wgtypes.Key, tlsEnabled bool) (*Client, error) { +func NewClient(ctx context.Context, addr string, ourPrivateKey wgtypes.Key, tlsEnabled bool) (*Client, error) { transportOption := grpc.WithInsecure() @@ -49,7 +49,7 @@ func NewClient(ctx context.Context, addr string, outPrivateKey wgtypes.Key, tlsE realClient := proto.NewManagementServiceClient(conn) return &Client{ - key: outPrivateKey, + key: ourPrivateKey, realClient: realClient, ctx: ctx, conn: conn, @@ -62,6 +62,7 @@ func (c *Client) Close() error { } // Sync wraps the real client's Sync endpoint call and takes care of retries and encryption/decryption of messages +// Non blocking request (executed in go routine). The result will be sent via msgHandler callback function func (c *Client) Sync(msgHandler func(msg *proto.SyncResponse) error) { go func() { diff --git a/management/client/client_test.go b/management/client/client_test.go new file mode 100644 index 000000000..b3d0c2853 --- /dev/null +++ b/management/client/client_test.go @@ -0,0 +1,167 @@ +package client + +import ( + "context" + log "github.com/sirupsen/logrus" + mgmtProto "github.com/wiretrustee/wiretrustee/management/proto" + mgmt "github.com/wiretrustee/wiretrustee/management/server" + "github.com/wiretrustee/wiretrustee/util" + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "net" + "path/filepath" + "testing" + "time" +) + +var tested *Client +var serverAddr string + +func Test_Start(t *testing.T) { + level, _ := log.ParseLevel("debug") + log.SetLevel(level) + + testKey, err := wgtypes.GenerateKey() + if err != nil { + t.Fatal(err) + } + testDir := t.TempDir() + ctx := context.Background() + config := &mgmt.Config{} + _, err = util.ReadJson("../server/testdata/management.json", config) + if err != nil { + t.Fatal(err) + } + config.Datadir = testDir + err = util.CopyFileContents("../server/testdata/store.json", filepath.Join(testDir, "store.json")) + if err != nil { + t.Fatal(err) + } + _, listener := startManagement(config, t) + serverAddr = listener.Addr().String() + tested, err = NewClient(ctx, serverAddr, testKey, false) + if err != nil { + t.Fatal(err) + } +} + +func startManagement(config *mgmt.Config, t *testing.T) (*grpc.Server, net.Listener) { + lis, err := net.Listen("tcp", ":0") + if err != nil { + t.Fatal(err) + } + s := grpc.NewServer() + store, err := mgmt.NewStore(config.Datadir) + if err != nil { + t.Fatal(err) + } + + accountManager := mgmt.NewManager(store) + mgmtServer, err := mgmt.NewServer(config, accountManager) + if err != nil { + t.Fatal(err) + } + mgmtProto.RegisterManagementServiceServer(s, mgmtServer) + go func() { + if err := s.Serve(lis); err != nil { + t.Error(err) + return + } + }() + + return s, lis +} + +func TestClient_GetServerPublicKey(t *testing.T) { + + key, err := tested.GetServerPublicKey() + if err != nil { + t.Error(err) + } + + if key == nil { + t.Error("expecting non nil server key got nil") + } +} + +func TestClient_LoginUnregistered_ShouldThrow_401(t *testing.T) { + key, err := tested.GetServerPublicKey() + if err != nil { + t.Fatal(err) + } + _, err = tested.Login(*key) + if err == nil { + t.Error("expecting err on unregistered login, got nil") + } + if s, ok := status.FromError(err); !ok || s.Code() != codes.PermissionDenied { + t.Errorf("expecting err code %d denied on on unregistered login got %d", codes.PermissionDenied, s.Code()) + } +} + +func TestClient_LoginRegistered(t *testing.T) { + key, err := tested.GetServerPublicKey() + if err != nil { + t.Error(err) + } + resp, err := tested.Register(*key, "a2c8e62b-38f5-4553-b31e-dd66c696cebb") + if err != nil { + t.Error(err) + } + + if resp == nil { + t.Error("expecting non nil response, got nil") + } +} + +func TestClient_Sync(t *testing.T) { + serverKey, err := tested.GetServerPublicKey() + if err != nil { + t.Error(err) + } + + _, err = tested.Register(*serverKey, "a2c8e62b-38f5-4553-b31e-dd66c696cebb") + if err != nil { + t.Error(err) + } + + // create and register second peer (we should receive on Sync request) + remoteKey, err := wgtypes.GenerateKey() + if err != nil { + t.Error(err) + } + remoteClient, err := NewClient(context.TODO(), serverAddr, remoteKey, false) + if err != nil { + t.Fatal(err) + } + _, err = remoteClient.Register(*serverKey, "a2c8e62b-38f5-4553-b31e-dd66c696cebb") + if err != nil { + t.Fatal(err) + } + + ch := make(chan *mgmtProto.SyncResponse, 1) + + tested.Sync(func(msg *mgmtProto.SyncResponse) error { + ch <- msg + return nil + }) + + select { + case resp := <-ch: + if resp.GetPeerConfig() == nil { + t.Error("expecting non nil PeerConfig got nil") + } + if resp.GetWiretrusteeConfig() == nil { + t.Error("expecting non nil WiretrusteeConfig got nil") + } + if len(resp.GetRemotePeers()) != 1 { + t.Errorf("expecting RemotePeers size %d got %d", 1, len(resp.GetRemotePeers())) + } + if resp.GetRemotePeers()[0].GetWgPubKey() != remoteKey.PublicKey().String() { + t.Errorf("expecting RemotePeer public key %s got %s", remoteKey.PublicKey().String(), resp.GetRemotePeers()[0].GetWgPubKey()) + } + case <-time.After(3 * time.Second): + t.Error("timeout waiting for test to finish") + } +} diff --git a/management/cmd/management.go b/management/cmd/management.go index a158ee11c..223d542a3 100644 --- a/management/cmd/management.go +++ b/management/cmd/management.go @@ -5,7 +5,6 @@ import ( "flag" "fmt" "github.com/wiretrustee/wiretrustee/management/server" - grpc2 "github.com/wiretrustee/wiretrustee/management/server/grpc" "github.com/wiretrustee/wiretrustee/management/server/http" "github.com/wiretrustee/wiretrustee/util" "net" @@ -79,7 +78,7 @@ var ( opts = append(opts, grpc.KeepaliveEnforcementPolicy(kaep), grpc.KeepaliveParams(kasp)) grpcServer := grpc.NewServer(opts...) - server, err := grpc2.NewServer(config, accountManager) + server, err := server.NewServer(config, accountManager) if err != nil { log.Fatalf("failed creating new server: %v", err) } diff --git a/management/server/grpc/server.go b/management/server/grpcserver.go similarity index 92% rename from management/server/grpc/server.go rename to management/server/grpcserver.go index 54a1d9dce..382755a8a 100644 --- a/management/server/grpc/server.go +++ b/management/server/grpcserver.go @@ -1,9 +1,8 @@ -package grpc +package server import ( "context" "fmt" - "github.com/wiretrustee/wiretrustee/management/server" "sync" "time" @@ -18,12 +17,12 @@ import ( // Server an instance of a Management server type Server struct { - accountManager *server.AccountManager + accountManager *AccountManager wgKey wgtypes.Key proto.UnimplementedManagementServiceServer peerChannels map[string]chan *UpdateChannelMessage channelsMux *sync.Mutex - config *server.Config + config *Config } // AllowedIPsFormat generates Wireguard AllowedIPs format (e.g. 100.30.30.1/32) @@ -34,7 +33,7 @@ type UpdateChannelMessage struct { } // NewServer creates a new Management server -func NewServer(config *server.Config, accountManager *server.AccountManager) (*Server, error) { +func NewServer(config *Config, accountManager *AccountManager) (*Server, error) { key, err := wgtypes.GeneratePrivateKey() if err != nil { return nil, err @@ -126,7 +125,7 @@ func (s *Server) Sync(req *proto.EncryptedMessage, srv proto.ManagementService_S } } -func (s *Server) registerPeer(peerKey wgtypes.Key, setupKey string) (*server.Peer, error) { +func (s *Server) registerPeer(peerKey wgtypes.Key, setupKey string) (*Peer, error) { s.channelsMux.Lock() defer s.channelsMux.Unlock() @@ -144,7 +143,7 @@ func (s *Server) registerPeer(peerKey wgtypes.Key, setupKey string) (*server.Pee for _, remotePeer := range peers { if channel, ok := s.peerChannels[remotePeer.Key]; ok { // exclude notified peer and add ourselves - peersToSend := []*server.Peer{peer} + peersToSend := []*Peer{peer} for _, p := range peers { if remotePeer.Key != p.Key { peersToSend = append(peersToSend, p) @@ -214,17 +213,17 @@ func (s *Server) Login(ctx context.Context, req *proto.EncryptedMessage) (*proto }, nil } -func toResponseProto(configProto server.Protocol) proto.HostConfig_Protocol { +func toResponseProto(configProto Protocol) proto.HostConfig_Protocol { switch configProto { - case server.UDP: + case UDP: return proto.HostConfig_UDP - case server.DTLS: + case DTLS: return proto.HostConfig_DTLS - case server.HTTP: + case HTTP: return proto.HostConfig_HTTP - case server.HTTPS: + case HTTPS: return proto.HostConfig_HTTPS - case server.TCP: + case TCP: return proto.HostConfig_TCP default: //mbragin: todo something better? @@ -232,7 +231,7 @@ func toResponseProto(configProto server.Protocol) proto.HostConfig_Protocol { } } -func toWiretrusteeConfig(config *server.Config) *proto.WiretrusteeConfig { +func toWiretrusteeConfig(config *Config) *proto.WiretrusteeConfig { var stuns []*proto.HostConfig for _, stun := range config.Stuns { @@ -263,13 +262,13 @@ func toWiretrusteeConfig(config *server.Config) *proto.WiretrusteeConfig { } } -func toPeerConfig(peer *server.Peer) *proto.PeerConfig { +func toPeerConfig(peer *Peer) *proto.PeerConfig { return &proto.PeerConfig{ Address: peer.IP.String() + "/24", //todo make it explicit } } -func toSyncResponse(config *server.Config, peer *server.Peer, peers []*server.Peer) *proto.SyncResponse { +func toSyncResponse(config *Config, peer *Peer, peers []*Peer) *proto.SyncResponse { wtConfig := toWiretrusteeConfig(config) @@ -324,7 +323,7 @@ func (s *Server) closeUpdatesChannel(peerKey string) { } // sendInitialSync sends initial proto.SyncResponse to the peer requesting synchronization -func (s *Server) sendInitialSync(peerKey wgtypes.Key, peer *server.Peer, srv proto.ManagementService_SyncServer) error { +func (s *Server) sendInitialSync(peerKey wgtypes.Key, peer *Peer, srv proto.ManagementService_SyncServer) error { peers, err := s.accountManager.GetPeersForAPeer(peer.Key) if err != nil { diff --git a/management/server/management_test.go b/management/server/management_test.go index f3ebddf81..ad5cb135f 100644 --- a/management/server/management_test.go +++ b/management/server/management_test.go @@ -3,7 +3,6 @@ package server_test import ( "context" server "github.com/wiretrustee/wiretrustee/management/server" - grpc2 "github.com/wiretrustee/wiretrustee/management/server/grpc" "io/ioutil" "math/rand" "net" @@ -484,7 +483,7 @@ func startServer(config *server.Config) (*grpc.Server, net.Listener) { log.Fatalf("failed creating a store: %s: %v", config.Datadir, err) } accountManager := server.NewManager(store) - mgmtServer, err := grpc2.NewServer(config, accountManager) + mgmtServer, err := server.NewServer(config, accountManager) Expect(err).NotTo(HaveOccurred()) mgmtProto.RegisterManagementServiceServer(s, mgmtServer) go func() {