Commit 26d4a441 authored by Caro Axel's avatar Caro Axel

Merge branch '264_net_tests' into 'master'

264 net tests

- Support for non-auth client improved
- Removed fatal in favor of error returns
- Add tests and examples

See merge request !16
parents 5dbdede2 b92ff0a0
Pipeline #192 passed with stage
......@@ -22,6 +22,7 @@ Unit tests:
- "go test -coverprofile auth.part -v dfss/auth"
- "go test -coverprofile mgdb.part -v dfss/mgdb"
- "go test -coverprofile mails.part -v dfss/mails"
- "go test -coverprofile net.part -v dfss/net"
- "go test -coverprofile authority.part -v dfss/dfssp/authority"
- "echo 'mode: set' *part > c.out"
- "grep -h -v 'mode: set' *part >> c.out"
......@@ -36,6 +37,7 @@ ARM tests:
- "./build/deps.sh"
- "go test -cover -short -v dfss/auth"
- "go test -cover -short -v dfss/mgdb"
- "go test -cover -short -v dfss/net"
- "go test -cover -short -v dfss/dfssp/authority"
Code lint:
......@@ -48,6 +50,6 @@ Code lint:
- "ln -s $(pwd) $GOPATH/src/dfss"
- "go get github.com/alecthomas/gometalinter"
- "./build/deps.sh"
- "go install ./..."
- "cd $GOPATH/src/dfss && go install ./..."
- "gometalinter --install"
- "gometalinter -t --deadline=300s -j1 --skip=api --skip=fixtures ./..."
......@@ -3,37 +3,41 @@ package net
import (
"crypto/tls"
"crypto/x509"
"log"
"errors"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/grpclog"
)
// Connect to a peer.
//
// Given parameters cert/key/ca are PEM-encoded array of bytes.
// Closing must be defered after call.
func Connect(addrPort string, cert, key, ca []byte) *grpc.ClientConn {
// load peer cert/key, ca as PEM buffers
peerCert, err := tls.X509KeyPair(cert, key)
if err != nil {
log.Fatalf("Load peer cert/key error: %v", err)
func Connect(addrPort string, cert, key, ca []byte) (*grpc.ClientConn, error) {
var certificates = make([]tls.Certificate, 1)
if len(key) > 0 && len(cert) > 0 {
// load peer cert/key, ca as PEM buffers
peerCert, err := tls.X509KeyPair(cert, key)
if err != nil {
return nil, err
}
certificates = append(certificates, peerCert)
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(ca)
ok := caCertPool.AppendCertsFromPEM(ca)
if !ok {
return nil, errors.New("Bad format for CA")
}
// configure transport authentificator
ta := credentials.NewTLS(&tls.Config{
Certificates: []tls.Certificate{peerCert},
Certificates: certificates,
RootCAs: caCertPool,
})
// let's do the dialing !
con, err := grpc.Dial(addrPort, grpc.WithTransportCredentials(ta))
if err != nil {
grpclog.Fatalf("Fail to dial: %v", err)
}
return con
return grpc.Dial(addrPort, grpc.WithTransportCredentials(ta))
}
all:
protoc --go_out=plugins=grpc:. test.proto
// Code generated by protoc-gen-go.
// source: test.proto
// DO NOT EDIT!
/*
Package fixtures is a generated protocol buffer package.
It is generated from these files:
test.proto
It has these top-level messages:
Hop
IsAuth
Empty
*/
package fixtures
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import (
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
const _ = proto.ProtoPackageIsVersion1
type Hop struct {
Id int32 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"`
}
func (m *Hop) Reset() { *m = Hop{} }
func (m *Hop) String() string { return proto.CompactTextString(m) }
func (*Hop) ProtoMessage() {}
func (*Hop) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
type IsAuth struct {
Auth bool `protobuf:"varint,1,opt,name=auth" json:"auth,omitempty"`
}
func (m *IsAuth) Reset() { *m = IsAuth{} }
func (m *IsAuth) String() string { return proto.CompactTextString(m) }
func (*IsAuth) ProtoMessage() {}
func (*IsAuth) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
type Empty struct {
}
func (m *Empty) Reset() { *m = Empty{} }
func (m *Empty) String() string { return proto.CompactTextString(m) }
func (*Empty) ProtoMessage() {}
func (*Empty) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
func init() {
proto.RegisterType((*Hop)(nil), "fixtures.Hop")
proto.RegisterType((*IsAuth)(nil), "fixtures.IsAuth")
proto.RegisterType((*Empty)(nil), "fixtures.Empty")
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn
// Client API for Test service
type TestClient interface {
Ping(ctx context.Context, in *Hop, opts ...grpc.CallOption) (*Hop, error)
Auth(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*IsAuth, error)
}
type testClient struct {
cc *grpc.ClientConn
}
func NewTestClient(cc *grpc.ClientConn) TestClient {
return &testClient{cc}
}
func (c *testClient) Ping(ctx context.Context, in *Hop, opts ...grpc.CallOption) (*Hop, error) {
out := new(Hop)
err := grpc.Invoke(ctx, "/fixtures.Test/Ping", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *testClient) Auth(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*IsAuth, error) {
out := new(IsAuth)
err := grpc.Invoke(ctx, "/fixtures.Test/Auth", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for Test service
type TestServer interface {
Ping(context.Context, *Hop) (*Hop, error)
Auth(context.Context, *Empty) (*IsAuth, error)
}
func RegisterTestServer(s *grpc.Server, srv TestServer) {
s.RegisterService(&_Test_serviceDesc, srv)
}
func _Test_Ping_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error) (interface{}, error) {
in := new(Hop)
if err := dec(in); err != nil {
return nil, err
}
out, err := srv.(TestServer).Ping(ctx, in)
if err != nil {
return nil, err
}
return out, nil
}
func _Test_Auth_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error) (interface{}, error) {
in := new(Empty)
if err := dec(in); err != nil {
return nil, err
}
out, err := srv.(TestServer).Auth(ctx, in)
if err != nil {
return nil, err
}
return out, nil
}
var _Test_serviceDesc = grpc.ServiceDesc{
ServiceName: "fixtures.Test",
HandlerType: (*TestServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Ping",
Handler: _Test_Ping_Handler,
},
{
MethodName: "Auth",
Handler: _Test_Auth_Handler,
},
},
Streams: []grpc.StreamDesc{},
}
var fileDescriptor0 = []byte{
// 152 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xe2, 0x2a, 0x49, 0x2d, 0x2e,
0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x48, 0xcb, 0xac, 0x28, 0x29, 0x2d, 0x4a, 0x2d,
0x56, 0x12, 0xe5, 0x62, 0xf6, 0xc8, 0x2f, 0x10, 0xe2, 0xe3, 0x62, 0xca, 0x4c, 0x91, 0x60, 0x54,
0x60, 0xd4, 0x60, 0x0d, 0x02, 0xb2, 0x94, 0x64, 0xb8, 0xd8, 0x3c, 0x8b, 0x1d, 0x4b, 0x4b, 0x32,
0x84, 0x84, 0xb8, 0x58, 0x12, 0x81, 0x34, 0x58, 0x8e, 0x23, 0x08, 0xcc, 0x56, 0x62, 0xe7, 0x62,
0x75, 0xcd, 0x2d, 0x28, 0xa9, 0x34, 0x8a, 0xe6, 0x62, 0x09, 0x01, 0x9a, 0x2a, 0xa4, 0xc6, 0xc5,
0x12, 0x90, 0x99, 0x97, 0x2e, 0xc4, 0xab, 0x07, 0x33, 0x58, 0x0f, 0x68, 0xaa, 0x14, 0x2a, 0x57,
0x89, 0x41, 0x48, 0x9b, 0x8b, 0x05, 0x6c, 0x28, 0x3f, 0x42, 0x02, 0x6c, 0x90, 0x94, 0x00, 0x42,
0x00, 0x62, 0xaf, 0x12, 0x43, 0x12, 0x1b, 0xd8, 0xad, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff,
0x03, 0x4e, 0x65, 0x96, 0xb9, 0x00, 0x00, 0x00,
}
syntax = "proto3";
package fixtures;
service Test {
rpc Ping(Hop) returns (Hop) {}
rpc Auth(Empty) returns (IsAuth) {}
}
message Hop {
int32 id = 1;
}
message IsAuth {
bool auth = 1;
}
message Empty {}
package net
import (
"fmt"
"net"
"testing"
"time"
pb "dfss/net/fixtures"
"golang.org/x/net/context"
)
const caFixture = `-----BEGIN CERTIFICATE-----
MIIB5TCCAY+gAwIBAgIJAKId2y6Lo9T8MA0GCSqGSIb3DQEBCwUAME0xCzAJBgNV
BAYTAkZSMQ0wCwYDVQQKDARERlNTMRswGQYDVQQLDBJERlNTIFBsYXRmb3JtIHYw
LjExEjAQBgNVBAMMCWxvY2FsaG9zdDAgFw0xNjAxMjYxNTM2NTNaGA80NDgwMDMw
ODE1MzY1M1owTTELMAkGA1UEBhMCRlIxDTALBgNVBAoMBERGU1MxGzAZBgNVBAsM
EkRGU1MgUGxhdGZvcm0gdjAuMTESMBAGA1UEAwwJbG9jYWxob3N0MFwwDQYJKoZI
hvcNAQEBBQADSwAwSAJBAMGAgCtkRLePYFRTUN0V/0v/6phm0guHGS6f0TkSEas4
CGZTKFJVTBksMGIBtfyYw3XQx2bO8myeypDN5nV05DcCAwEAAaNQME4wHQYDVR0O
BBYEFO09nxx5/qeLK5Wig1+3kg66gn/mMB8GA1UdIwQYMBaAFO09nxx5/qeLK5Wi
g1+3kg66gn/mMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADQQCqNSH+rt/Z
ru2rkabLiHOGjI+AenSOvqWZ2dWAlLksYcyuQHKwjGWgpmqkiQCnkIDwIxZvu69Y
OBz0ASFn7eym
-----END CERTIFICATE-----
`
const serverKeyFixture = `-----BEGIN RSA PRIVATE KEY-----
MIIBOwIBAAJBAMGAgCtkRLePYFRTUN0V/0v/6phm0guHGS6f0TkSEas4CGZTKFJV
TBksMGIBtfyYw3XQx2bO8myeypDN5nV05DcCAwEAAQJAHSdRKDh5KfbOGqZa3pR7
3GV4YPHM37PBFYc6rJCOXO9W8L4Q1kvEhjKXp7ke18Cge7bVmlKspvxvC62gxSQm
QQIhAPMYwpp29ZREdk8yU65Sp6w+EbZS9TjZkC+pk3syYjaxAiEAy8XWnnDMsUxb
6vp1SaaIfxI441AYzh3+8c56CAvt02cCIQDQ2jfvHz7zyDHg7rsILMkTaSwseW9n
DTwcRtOHZ40LsQIgDWEVAVwopG9+DYSaVNahWa6Jm6szpbzkc136NzMJT3sCIQDv
T2KSQQIYEvPYZmE+1b9f3rs/w7setrGtqVFkm/fTWQ==
-----END RSA PRIVATE KEY-----
`
const clientCertFixture = `-----BEGIN CERTIFICATE-----
MIIBkDCCAToCCQDSSWVk2vWTdjANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQGEwJG
UjENMAsGA1UECgwEREZTUzEbMBkGA1UECwwSREZTUyBQbGF0Zm9ybSB2MC4xMRIw
EAYDVQQDDAlsb2NhbGhvc3QwIBcNMTYwMTI2MTUzNjUzWhgPNDQ4MDAzMDgxNTM2
NTNaME8xCzAJBgNVBAYTAkZSMQ0wCwYDVQQKDARERlNTMRkwFwYDVQQLDBBERlNT
IENsaWVudCB2MC4xMRYwFAYDVQQDDA10ZXN0QHRlc3QuY29tMFwwDQYJKoZIhvcN
AQEBBQADSwAwSAJBAMxHU0NP/elQbmM5HDZS5iWXr4wllaJ2bWWD0cZPI1p+jty0
wwkKwxEklPGZCDWq1+/C4EawaqMrtZW4HQVxdu8CAwEAATANBgkqhkiG9w0BAQsF
AANBACl2/KBGR8N4qzpNecr1yDdyfyE4nGYgr8aktAeHHNWFg53q3/VHokK0jEus
iM6sQlvDCoaE01s6gXrarE+APfU=
-----END CERTIFICATE-----
`
const clientKeyFixture = `-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBAMxHU0NP/elQbmM5HDZS5iWXr4wllaJ2bWWD0cZPI1p+jty0wwkK
wxEklPGZCDWq1+/C4EawaqMrtZW4HQVxdu8CAwEAAQJBAIBwYCO0idtGnQF6CQkG
+nmsc83UW874UzQ+u4jKfVoJlB+Llp7Y6iFhyS+Trw+ffpT32hYtoX+cRxWVh+g3
xOECIQD6S/gPG3dCJWGsZ7/V6WVOfzdz6VAHtBjfgYNMLZQhZwIhANDu7FpmhxWm
nVr3u6hLKY28Zhp03LqsljfEoWEkAmE5AiBPreV+8bBqZzoLx09jipRMg+UkSi7G
9QdCB5nDo3LXmwIgFGdArZNVncenljqbGNQ+OpkrX2oKJDC2eru5BsN9eAECIFXi
HBs0FRZQlpn1kXgfvakOtkifTcLaksnn3Y5PAEhP
-----END RSA PRIVATE KEY-----
`
// SERVER DEFINITION
type testServer struct{}
func (s *testServer) Ping(ctx context.Context, in *pb.Hop) (*pb.Hop, error) {
(*in).Id++
return in, nil
}
func (s *testServer) Auth(ctx context.Context, in *pb.Empty) (*pb.IsAuth, error) {
return &pb.IsAuth{Auth: GetCN(&ctx) == "test@test.com"}, nil
}
func startTestServer(c chan bool) {
server := NewServer([]byte(caFixture), []byte(serverKeyFixture), []byte(caFixture))
pb.RegisterTestServer(server, &testServer{})
go func() {
_ = Listen("localhost:9000", server)
}()
<-c
server.TestingCloseConns()
server.Stop()
}
// TESTS
func TestServerOnly(t *testing.T) {
c := make(chan bool)
go startTestServer(c)
time.Sleep(2 * time.Second) // Two seconds to start
_, err := net.Dial("tcp", "localhost:9000")
if err != nil {
t.Fatal("Unable to bind to server:", err)
}
c <- true // Stop server
time.Sleep(100 * time.Millisecond)
}
func TestServerClientAuth(t *testing.T) {
// Start server
c := make(chan bool)
go startTestServer(c)
time.Sleep(2 * time.Second)
conn, err := Connect("localhost:9000", []byte(clientCertFixture), []byte(clientKeyFixture), []byte(caFixture))
if err != nil {
t.Fatal("Unable to connect:", err)
}
client := pb.NewTestClient(conn)
sharedServerClientTest(t, client, true)
_ = conn.Close()
c <- true
time.Sleep(100 * time.Millisecond)
}
func TestServerClientNonAuth(t *testing.T) {
// Start server
c := make(chan bool)
go startTestServer(c)
time.Sleep(2 * time.Second)
conn, err := Connect("localhost:9000", []byte{}, []byte{}, []byte(caFixture))
if err != nil {
t.Fatal("Unable to connect:", err)
}
client := pb.NewTestClient(conn)
sharedServerClientTest(t, client, false)
_ = conn.Close()
c <- true
time.Sleep(100 * time.Millisecond)
}
func sharedServerClientTest(t *testing.T, client pb.TestClient, expectedAuth bool) {
r, err := client.Ping(context.Background(), &pb.Hop{Id: 0})
if err != nil {
t.Fatal("Unable to ping:", err)
}
if (*r).Id != 1 {
t.Fatal("Bad result, got", *r)
}
auth, err := client.Auth(context.Background(), &pb.Empty{})
if err != nil {
t.Fatal("Unable to auth:", err)
}
if expectedAuth != (*auth).Auth {
t.Fatal("Bad result, got", *auth)
}
}
// EXAMPLE
func Example() {
// Init server
server := NewServer([]byte(caFixture), []byte(serverKeyFixture), []byte(caFixture))
pb.RegisterTestServer(server, &testServer{})
go func() {
_ = Listen("localhost:9000", server)
}()
// Let the server enough time to start property
time.Sleep(2 * time.Second)
// Start a client
// The second and third arguments can be empty for non-auth connection
conn, err := Connect("localhost:9000", []byte(clientCertFixture), []byte(clientKeyFixture), []byte(caFixture))
if err != nil {
panic("Unable to connect")
}
client := pb.NewTestClient(conn)
// During a ping, the server increments the Hop.Id field (test case only)
r, err := client.Ping(context.Background(), &pb.Hop{Id: 41})
if err != nil {
panic("Unable to ping")
}
fmt.Println((*r).Id)
// Close client
_ = conn.Close()
// Stop server
server.Stop()
// Output:
// 42
}
......@@ -3,13 +3,13 @@ package net
import (
"crypto/tls"
"crypto/x509"
"log"
"net"
"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/peer"
"log"
"net"
)
// NewServer creates a new grpc server with given tls credentials.
......@@ -44,17 +44,13 @@ func NewServer(cert, key, ca []byte) *grpc.Server {
// Listen with specified server on addr:port.
//
// addrPort is formated as 127.0.0.1:8001.
func Listen(addrPort string, grpcServer *grpc.Server) {
func Listen(addrPort string, grpcServer *grpc.Server) error {
// open tcp socket
lis, err := net.Listen("tcp", addrPort)
if err != nil {
grpclog.Fatalf("Failed to open tcp socket: %v", err)
}
err = grpcServer.Serve(lis)
if err != nil {
grpclog.Fatalf("Failed to bind gRPC server: %v", err)
return err
}
return grpcServer.Serve(lis)
}
// GetTLSState returns the current tls connection state from a grpc context.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment