Skip to content

Commit

Permalink
Add ndt7test package for creating an ndt7 server for unit tests (#319)
Browse files Browse the repository at this point in the history
* Add ndt7/ndt7test
* Verify that TCPInfo is non-nil
* Add unit test for ndt7test logic
  • Loading branch information
stephen-soltesz authored Sep 10, 2020
1 parent f8bed0a commit 8da06dc
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 2 deletions.
6 changes: 4 additions & 2 deletions ndt7/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,8 @@ func getData(conn *websocket.Conn) (*model.ArchivalData, error) {

func upRate(m []model.Measurement) float64 {
var mbps float64
if len(m) > 0 {
// NOTE: on non-Linux platforms, TCPInfo will be nil.
if len(m) > 0 && m[len(m)-1].TCPInfo != nil {
// Convert to Mbps.
mbps = 8 * float64(m[len(m)-1].TCPInfo.BytesReceived) / float64(m[len(m)-1].TCPInfo.ElapsedTime)
}
Expand All @@ -197,7 +198,8 @@ func upRate(m []model.Measurement) float64 {

func downRate(m []model.Measurement) float64 {
var mbps float64
if len(m) > 0 {
// NOTE: on non-Linux platforms, TCPInfo will be nil.
if len(m) > 0 && m[len(m)-1].TCPInfo != nil {
// Convert to Mbps.
mbps = 8 * float64(m[len(m)-1].TCPInfo.BytesAcked) / float64(m[len(m)-1].TCPInfo.ElapsedTime)
}
Expand Down
41 changes: 41 additions & 0 deletions ndt7/ndt7test/ndt7test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package ndt7test

import (
"fmt"
"io/ioutil"
"net"
"net/http"
"net/http/httptest"
"testing"

"github.com/m-lab/go/testingx"
"github.com/m-lab/ndt-server/ndt7/handler"
"github.com/m-lab/ndt-server/ndt7/spec"
"github.com/m-lab/ndt-server/netx"
)

// NewNDT7Server creates a local httptest server capable of running an ndt7
// measurement in unittests.
func NewNDT7Server(t *testing.T) (*handler.Handler, *httptest.Server) {
dir, err := ioutil.TempDir("", "ndt7test-*")
testingx.Must(t, err, "failed to create temp dir")

// TODO: add support for token verifiers.
// TODO: add support for TLS server.
ndt7Handler := &handler.Handler{DataDir: dir}
ndt7Mux := http.NewServeMux()
ndt7Mux.Handle(spec.DownloadURLPath, http.HandlerFunc(ndt7Handler.Download))
ndt7Mux.Handle(spec.UploadURLPath, http.HandlerFunc(ndt7Handler.Upload))

// Create unstarted so we can setup a custom netx.Listener.
ts := httptest.NewUnstartedServer(ndt7Mux)
listener, err := net.Listen("tcp", ":0")
testingx.Must(t, err, "failed to allocate a listening tcp socket")
addr := (listener.(*net.TCPListener)).Addr().(*net.TCPAddr)
// Populate insecure port value with dynamic port.
ndt7Handler.InsecurePort = fmt.Sprintf(":%d", addr.Port)
ts.Listener = netx.NewListener(listener.(*net.TCPListener))
// Now that the test server has our custom listener, start it.
ts.Start()
return ndt7Handler, ts
}
66 changes: 66 additions & 0 deletions ndt7/ndt7test/ndt7test_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package ndt7test

import (
"context"
"net/http"
"net/url"
"os"
"path/filepath"
"testing"
"time"

"github.com/gorilla/websocket"
"github.com/m-lab/go/testingx"
"github.com/m-lab/ndt-server/ndt7/spec"
)

func TestNewNDT7Server(t *testing.T) {
// Create the ndt7test server.
h, srv := NewNDT7Server(t)
defer os.RemoveAll(h.DataDir)

// Prepare to run a simplified download with ndt7test server.
URL, _ := url.Parse(srv.URL)
URL.Scheme = "ws"
URL.Path = spec.DownloadURLPath
headers := http.Header{}
headers.Add("Sec-WebSocket-Protocol", spec.SecWebSocketProtocol)
headers.Add("User-Agent", "fake-user-agent")
ctx := context.Background()
dialer := websocket.Dialer{HandshakeTimeout: 10 * time.Second}
conn, _, err := dialer.DialContext(ctx, URL.String(), headers)
testingx.Must(t, err, "failed to dial websocket ndt7 test")
err = simpleDownload(ctx, t, conn)
if err != nil && !websocket.IsCloseError(err, websocket.CloseNormalClosure) {
testingx.Must(t, err, "failed to download")
}

// Allow the server time to save the file, the client may stop before the server does.
time.Sleep(1 * time.Second)
// Verify a file was saved.
m, err := filepath.Glob(h.DataDir + "/ndt7/*/*/*/*")
testingx.Must(t, err, "failed to glob datadir: %s", h.DataDir)
if len(m) == 0 {
t.Errorf("no files found")
}
}

func simpleDownload(ctx context.Context, t *testing.T, conn *websocket.Conn) error {
defer conn.Close()
wholectx, cancel := context.WithTimeout(ctx, spec.MaxRuntime)
defer cancel()
conn.SetReadLimit(spec.MaxMessageSize)
err := conn.SetReadDeadline(time.Now().Add(spec.MaxRuntime))
testingx.Must(t, err, "failed to set read deadline")

var total int64
// WARNING: this is not a reference client.
for wholectx.Err() == nil {
_, mdata, err := conn.ReadMessage()
if err != nil {
return err
}
total += int64(len(mdata))
}
return nil
}

0 comments on commit 8da06dc

Please sign in to comment.