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]
This commit is contained in:
Mikhail Bragin 2021-08-16 23:30:51 +02:00 committed by GitHub
parent 2a97053cae
commit e8ca289f4a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 188 additions and 197 deletions

View File

@ -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)
}
}

View File

@ -23,7 +23,7 @@ type Client struct {
} }
// NewClient creates a new client to Management service // 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() transportOption := grpc.WithInsecure()
@ -49,7 +49,7 @@ func NewClient(ctx context.Context, addr string, outPrivateKey wgtypes.Key, tlsE
realClient := proto.NewManagementServiceClient(conn) realClient := proto.NewManagementServiceClient(conn)
return &Client{ return &Client{
key: outPrivateKey, key: ourPrivateKey,
realClient: realClient, realClient: realClient,
ctx: ctx, ctx: ctx,
conn: conn, 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 // 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) { func (c *Client) Sync(msgHandler func(msg *proto.SyncResponse) error) {
go func() { go func() {

View File

@ -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")
}
}

View File

@ -5,7 +5,6 @@ import (
"flag" "flag"
"fmt" "fmt"
"github.com/wiretrustee/wiretrustee/management/server" "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/management/server/http"
"github.com/wiretrustee/wiretrustee/util" "github.com/wiretrustee/wiretrustee/util"
"net" "net"
@ -79,7 +78,7 @@ var (
opts = append(opts, grpc.KeepaliveEnforcementPolicy(kaep), grpc.KeepaliveParams(kasp)) opts = append(opts, grpc.KeepaliveEnforcementPolicy(kaep), grpc.KeepaliveParams(kasp))
grpcServer := grpc.NewServer(opts...) grpcServer := grpc.NewServer(opts...)
server, err := grpc2.NewServer(config, accountManager) server, err := server.NewServer(config, accountManager)
if err != nil { if err != nil {
log.Fatalf("failed creating new server: %v", err) log.Fatalf("failed creating new server: %v", err)
} }

View File

@ -1,9 +1,8 @@
package grpc package server
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/wiretrustee/wiretrustee/management/server"
"sync" "sync"
"time" "time"
@ -18,12 +17,12 @@ import (
// Server an instance of a Management server // Server an instance of a Management server
type Server struct { type Server struct {
accountManager *server.AccountManager accountManager *AccountManager
wgKey wgtypes.Key wgKey wgtypes.Key
proto.UnimplementedManagementServiceServer proto.UnimplementedManagementServiceServer
peerChannels map[string]chan *UpdateChannelMessage peerChannels map[string]chan *UpdateChannelMessage
channelsMux *sync.Mutex channelsMux *sync.Mutex
config *server.Config config *Config
} }
// AllowedIPsFormat generates Wireguard AllowedIPs format (e.g. 100.30.30.1/32) // 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 // 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() key, err := wgtypes.GeneratePrivateKey()
if err != nil { if err != nil {
return nil, err 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() s.channelsMux.Lock()
defer s.channelsMux.Unlock() defer s.channelsMux.Unlock()
@ -144,7 +143,7 @@ func (s *Server) registerPeer(peerKey wgtypes.Key, setupKey string) (*server.Pee
for _, remotePeer := range peers { for _, remotePeer := range peers {
if channel, ok := s.peerChannels[remotePeer.Key]; ok { if channel, ok := s.peerChannels[remotePeer.Key]; ok {
// exclude notified peer and add ourselves // exclude notified peer and add ourselves
peersToSend := []*server.Peer{peer} peersToSend := []*Peer{peer}
for _, p := range peers { for _, p := range peers {
if remotePeer.Key != p.Key { if remotePeer.Key != p.Key {
peersToSend = append(peersToSend, p) peersToSend = append(peersToSend, p)
@ -214,17 +213,17 @@ func (s *Server) Login(ctx context.Context, req *proto.EncryptedMessage) (*proto
}, nil }, nil
} }
func toResponseProto(configProto server.Protocol) proto.HostConfig_Protocol { func toResponseProto(configProto Protocol) proto.HostConfig_Protocol {
switch configProto { switch configProto {
case server.UDP: case UDP:
return proto.HostConfig_UDP return proto.HostConfig_UDP
case server.DTLS: case DTLS:
return proto.HostConfig_DTLS return proto.HostConfig_DTLS
case server.HTTP: case HTTP:
return proto.HostConfig_HTTP return proto.HostConfig_HTTP
case server.HTTPS: case HTTPS:
return proto.HostConfig_HTTPS return proto.HostConfig_HTTPS
case server.TCP: case TCP:
return proto.HostConfig_TCP return proto.HostConfig_TCP
default: default:
//mbragin: todo something better? //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 var stuns []*proto.HostConfig
for _, stun := range config.Stuns { 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{ return &proto.PeerConfig{
Address: peer.IP.String() + "/24", //todo make it explicit 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) wtConfig := toWiretrusteeConfig(config)
@ -324,7 +323,7 @@ func (s *Server) closeUpdatesChannel(peerKey string) {
} }
// sendInitialSync sends initial proto.SyncResponse to the peer requesting synchronization // 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) peers, err := s.accountManager.GetPeersForAPeer(peer.Key)
if err != nil { if err != nil {

View File

@ -3,7 +3,6 @@ package server_test
import ( import (
"context" "context"
server "github.com/wiretrustee/wiretrustee/management/server" server "github.com/wiretrustee/wiretrustee/management/server"
grpc2 "github.com/wiretrustee/wiretrustee/management/server/grpc"
"io/ioutil" "io/ioutil"
"math/rand" "math/rand"
"net" "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) log.Fatalf("failed creating a store: %s: %v", config.Datadir, err)
} }
accountManager := server.NewManager(store) accountManager := server.NewManager(store)
mgmtServer, err := grpc2.NewServer(config, accountManager) mgmtServer, err := server.NewServer(config, accountManager)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
mgmtProto.RegisterManagementServiceServer(s, mgmtServer) mgmtProto.RegisterManagementServiceServer(s, mgmtServer)
go func() { go func() {