Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve bytescount middleware tests #80

Merged
merged 3 commits into from Jan 3, 2018
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 6 additions & 14 deletions bytescount_client/middleware.go
Expand Up @@ -3,28 +3,23 @@ package bytescount_client
import (
"fmt"
"github.com/mysterium/node/openvpn"
"github.com/mysterium/node/server"
"github.com/mysterium/node/server/dto"
"github.com/mysterium/node/session"
"net"
"regexp"
"strconv"
"time"
)

type middleware struct {
mysteriumClient server.Client
interval time.Duration
sessionId session.SessionId
sessionStatsSender SessionStatsSender
interval time.Duration

connection net.Conn
}

func NewMiddleware(mysteriumClient server.Client, sessionId session.SessionId, interval time.Duration) openvpn.ManagementMiddleware {
func NewMiddleware(sessionStatsSender SessionStatsSender, interval time.Duration) openvpn.ManagementMiddleware {
return &middleware{
mysteriumClient: mysteriumClient,
interval: interval,
sessionId: sessionId,
sessionStatsSender: sessionStatsSender,
interval: interval,

connection: nil,
}
Expand Down Expand Up @@ -66,10 +61,7 @@ func (middleware *middleware) ConsumeLine(line string) (consumed bool, err error
return
}

err = middleware.mysteriumClient.SendSessionStats(string(middleware.sessionId), dto.SessionStats{
BytesSent: bytesOut,
BytesReceived: bytesIn,
})
err = middleware.sessionStatsSender.send(bytesOut, bytesIn)

return
}
90 changes: 75 additions & 15 deletions bytescount_client/middleware_test.go
Expand Up @@ -2,42 +2,102 @@ package bytescount_client

import (
"errors"
"github.com/mysterium/node/server"
"github.com/stretchr/testify/assert"
"net"
"testing"
"time"
)

type fakeConnection struct {
lastDataWritten []byte
}

func (conn *fakeConnection) Read(b []byte) (int, error) {
return 0, nil
}

func (conn *fakeConnection) Write(b []byte) (n int, err error) {
conn.lastDataWritten = b
return 0, nil
}

func (conn *fakeConnection) Close() error {
return nil
}

func (conn *fakeConnection) LocalAddr() net.Addr {
return nil
}

func (conn *fakeConnection) RemoteAddr() net.Addr {
return nil
}

func (conn *fakeConnection) SetDeadline(t time.Time) error {
return nil
}

func (conn *fakeConnection) SetReadDeadline(t time.Time) error {
return nil
}

func (conn *fakeConnection) SetWriteDeadline(t time.Time) error {
return nil
}

type fakeStatsSender struct {
lastBytesSent, lastBytesReceived int
}

func (sender *fakeStatsSender) send(bytesSent, bytesReceived int) error {
sender.lastBytesSent = bytesSent
sender.lastBytesReceived = bytesReceived
return nil
}

func Test_Factory(t *testing.T) {
middleware := NewMiddleware(server.NewClientFake(), "session-test", 1*time.Minute)
middleware := NewMiddleware(&fakeStatsSender{}, 1*time.Minute)
assert.NotNil(t, middleware)
}

func Test_Start(t *testing.T) {
statsSender := &fakeStatsSender{}
middleware := NewMiddleware(statsSender, 1*time.Minute)
connection := &fakeConnection{}
middleware.Start(connection)
assert.Equal(t, []byte("bytecount 60\n"), connection.lastDataWritten)
}

func Test_ConsumeLine(t *testing.T) {
var tests = []struct {
line string
expectedConsumed bool
expectedError error
line string
expectedConsumed bool
expectedError error
expectedBytesReceived int
expectedBytesSent int
}{
{">BYTECOUNT:3018,3264", true, nil},
{">BYTECOUNT:0,3264", true, nil},
{">BYTECOUNT:3018,", true, errors.New(`strconv.ParseInt: parsing "": invalid syntax`)},
{">BYTECOUNT:,", true, errors.New(`strconv.ParseInt: parsing "": invalid syntax`)},
{"OTHER", false, nil},
{"BYTECOUNT", false, nil},
{"BYTECOUNT:", false, nil},
{"BYTECOUNT:3018,3264", false, nil},
{">BYTECOUNTT:3018,3264", false, nil},
{">BYTECOUNT:3018,3264", true, nil, 3018, 3264},
{">BYTECOUNT:0,3264", true, nil, 0, 3264},
{">BYTECOUNT:3018,", true, errors.New(`strconv.ParseInt: parsing "": invalid syntax`), 0, 0},
{">BYTECOUNT:,", true, errors.New(`strconv.ParseInt: parsing "": invalid syntax`), 0, 0},
{"OTHER", false, nil, 0, 0},
{"BYTECOUNT", false, nil, 0, 0},
{"BYTECOUNT:", false, nil, 0, 0},
{"BYTECOUNT:3018,3264", false, nil, 0, 0},
{">BYTECOUNTT:3018,3264", false, nil, 0, 0},
}

middleware := NewMiddleware(server.NewClientFake(), "session-test", 1*time.Minute)
for _, test := range tests {
statsSender := &fakeStatsSender{}
middleware := NewMiddleware(statsSender, 1*time.Minute)
consumed, err := middleware.ConsumeLine(test.line)
if test.expectedError != nil {
assert.Error(t, test.expectedError, err.Error(), test.line)
} else {
assert.NoError(t, err, test.line)
}
assert.Equal(t, test.expectedConsumed, consumed, test.line)
assert.Equal(t, test.expectedBytesReceived, statsSender.lastBytesReceived)
assert.Equal(t, test.expectedBytesSent, statsSender.lastBytesSent)
}
}
26 changes: 26 additions & 0 deletions bytescount_client/stats_sender.go
@@ -0,0 +1,26 @@
package bytescount_client

import (
"github.com/mysterium/node/server"
"github.com/mysterium/node/server/dto"
)

type SessionStatsSender interface {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This struct look a bit excess, could be just custom-typed callback:

type SessionStatsSender func(sessionId string, bytesSent, bytesReceived int) error

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case, you would also need mysteriumClient server.Client parameter - having 4 parameters in function does not seem readable to me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, you would have to re-couple sessionId with middleware for this.

Copy link
Member

@Waldz Waldz Jan 3, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your factory can factory custom-typed function:

func NewSessionStatsSender(mysteriumClient server.Client, sessionId SessionId) SessionStatsSender {
     sessionIdString := string(sessionId)
     return SessionStatsSender(func() {
         mysteriumClient.SendSessionStats(sessionIdString, dto.SessionStats{})
     })
}

send(bytesSent, bytesReceived int) error
}

type clientSessionStatsSender struct {
mysteriumClient server.Client
sessionId string
}

func (sender *clientSessionStatsSender) send(bytesSent, bytesReceived int) error {
return sender.mysteriumClient.SendSessionStats(sender.sessionId, dto.SessionStats{
BytesSent: bytesSent,
BytesReceived: bytesReceived,
})
}

func NewSessionStatsSender(mysteriumClient server.Client, sessionId string) SessionStatsSender {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pass SessionId object here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

return &clientSessionStatsSender{mysteriumClient, sessionId}
}
3 changes: 2 additions & 1 deletion client_connection/manager.go
Expand Up @@ -121,8 +121,9 @@ func ConfigureVpnClientFactory(mysteriumApiClient server.Client, vpnClientRuntim
return nil, err
}

statsSender := bytescount_client.NewSessionStatsSender(mysteriumApiClient, string(vpnSession.Id))
vpnMiddlewares := []openvpn.ManagementMiddleware{
bytescount_client.NewMiddleware(mysteriumApiClient, vpnSession.Id, 1*time.Minute),
bytescount_client.NewMiddleware(statsSender, 1*time.Minute),
}
return openvpn.NewClient(
vpnConfig,
Expand Down