reflector.go/reflector/server_test.go
2019-10-03 16:49:28 -04:00

253 lines
5 KiB
Go

package reflector
import (
"crypto/rand"
"encoding/json"
"io"
"sort"
"strconv"
"testing"
"time"
"github.com/lbryio/lbry.go/dht/bits"
"github.com/lbryio/reflector.go/store"
"github.com/davecgh/go-spew/spew"
"github.com/phayes/freeport"
)
func startServerOnRandomPort(t *testing.T) (*Server, int) {
port, err := freeport.GetFreePort()
if err != nil {
t.Fatal(err)
}
srv := NewServer(store.NewMemoryBlobStore())
err = srv.Start("127.0.0.1:" + strconv.Itoa(port))
if err != nil {
t.Fatal(err)
}
return srv, port
}
func TestClient_NotConnected(t *testing.T) {
c := Client{}
err := c.SendBlob([]byte{})
if err == nil {
t.Error("client should error if it is not connected")
}
}
func TestClient_EmptyBlob(t *testing.T) {
srv, port := startServerOnRandomPort(t)
defer srv.Shutdown()
c := Client{}
err := c.Connect(":" + strconv.Itoa(port))
if err != nil {
t.Fatal("error connecting client to server", err)
}
err = c.SendBlob([]byte{})
if err == nil {
t.Error("client should not send empty blob")
}
}
func TestServer_MediumBlob(t *testing.T) {
srv, port := startServerOnRandomPort(t)
defer srv.Shutdown()
c := Client{}
err := c.Connect(":" + strconv.Itoa(port))
if err != nil {
t.Fatal("error connecting client to server", err)
}
blob := randBlob(1000)
err = c.SendBlob(blob)
if err != nil {
t.Error(err)
}
}
func TestServer_FullBlob(t *testing.T) {
srv, port := startServerOnRandomPort(t)
defer srv.Shutdown()
c := Client{}
err := c.Connect(":" + strconv.Itoa(port))
if err != nil {
t.Fatal("error connecting client to server", err)
}
blob := randBlob(maxBlobSize)
err = c.SendBlob(blob)
if err != nil {
t.Error(err)
}
}
func TestServer_TooBigBlob(t *testing.T) {
srv, port := startServerOnRandomPort(t)
defer srv.Shutdown()
c := Client{}
err := c.Connect(":" + strconv.Itoa(port))
if err != nil {
t.Fatal("error connecting client to server", err)
}
blob := randBlob(maxBlobSize + 1)
err = c.SendBlob(blob)
if err == nil {
t.Error("server should reject blob above max size")
}
}
func TestServer_Timeout(t *testing.T) {
t.Skip("server and client have no way to detect errors right now")
testTimeout := 50 * time.Millisecond
port, err := freeport.GetFreePort()
if err != nil {
t.Fatal(err)
}
srv := NewServer(store.NewMemoryBlobStore())
srv.Timeout = testTimeout
err = srv.Start("127.0.0.1:" + strconv.Itoa(port))
if err != nil {
t.Fatal(err)
}
defer srv.Shutdown()
c := Client{}
err = c.Connect(":" + strconv.Itoa(port))
if err != nil {
t.Fatal("error connecting client to server", err)
}
time.Sleep(testTimeout * 2)
blob := randBlob(10)
err = c.SendBlob(blob)
t.Log(spew.Sdump(err))
if err != io.EOF {
t.Error("server should have timed out by now")
}
}
//func TestServer_InvalidJSONHandshake(t *testing.T) {
// srv, port := startServerOnRandomPort(t)
// defer srv.Shutdown()
//
// c := Client{}
// err := c.Connect(":" + strconv.Itoa(port))
// if err != nil {
// t.Fatal("error connecting client to server", err)
// }
//
// _, err = c.conn.Write([]byte(`{"stuff":4,tf}"`))
// if err == nil {
// t.Error("expected an error")
// }
//}
type mockPartialStore struct {
*store.MemoryBlobStore
missing []string
}
func (m mockPartialStore) MissingBlobsForKnownStream(hash string) ([]string, error) {
return m.missing, nil
}
func TestServer_PartialUpload(t *testing.T) {
port, err := freeport.GetFreePort()
if err != nil {
t.Fatal(err)
}
sdHash := bits.Rand().String()
missing := make([]string, 4)
for i := range missing {
missing[i] = bits.Rand().String()
}
st := store.BlobStore(&mockPartialStore{MemoryBlobStore: store.NewMemoryBlobStore(), missing: missing})
if _, ok := st.(neededBlobChecker); !ok {
t.Fatal("mock does not implement the relevant interface")
}
err = st.Put(sdHash, randBlob(10))
if err != nil {
t.Fatal(err)
}
srv := NewServer(st)
err = srv.Start("127.0.0.1:" + strconv.Itoa(port))
if err != nil {
t.Fatal(err)
}
defer srv.Shutdown()
c := Client{}
err = c.Connect(":" + strconv.Itoa(port))
if err != nil {
t.Fatal("error connecting client to server", err)
}
sendRequest, err := json.Marshal(sendBlobRequest{
SdBlobHash: sdHash,
SdBlobSize: len(sdHash),
})
if err != nil {
t.Fatal(err)
}
_, err = c.conn.Write(sendRequest)
if err != nil {
t.Fatal(err)
}
var sendResp sendSdBlobResponse
err = json.NewDecoder(c.conn).Decode(&sendResp)
if err != nil {
t.Fatal(err)
}
if sendResp.SendSdBlob {
t.Errorf("expected SendSdBlob = false, got true")
}
if len(sendResp.NeededBlobs) != len(missing) {
t.Fatalf("got %d needed blobs, expected %d", len(sendResp.NeededBlobs), len(missing))
}
sort.Strings(sendResp.NeededBlobs)
sort.Strings(missing)
for i := range missing {
if missing[i] != sendResp.NeededBlobs[i] {
t.Errorf("needed blobs mismatch: %s != %s", missing[i], sendResp.NeededBlobs[i])
}
}
}
func randBlob(size int) []byte {
//if size > maxBlobSize {
// panic("blob size too big")
//}
blob := make([]byte, size)
_, err := rand.Read(blob)
if err != nil {
panic("failed to make random blob")
}
return blob
}