2018-08-09 20:56:49 +02:00
|
|
|
package reflector
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/rand"
|
2018-09-20 20:24:30 +02:00
|
|
|
"encoding/json"
|
2018-08-09 20:56:49 +02:00
|
|
|
"io"
|
2018-09-20 20:24:30 +02:00
|
|
|
"sort"
|
2018-08-09 20:56:49 +02:00
|
|
|
"strconv"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2019-11-14 01:11:35 +01:00
|
|
|
"github.com/lbryio/lbry.go/v2/dht/bits"
|
2018-08-09 20:56:49 +02:00
|
|
|
"github.com/lbryio/reflector.go/store"
|
|
|
|
|
2018-08-20 23:50:39 +02:00
|
|
|
"github.com/davecgh/go-spew/spew"
|
2018-08-09 20:56:49 +02:00
|
|
|
"github.com/phayes/freeport"
|
|
|
|
)
|
|
|
|
|
|
|
|
func startServerOnRandomPort(t *testing.T) (*Server, int) {
|
|
|
|
port, err := freeport.GetFreePort()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2021-01-06 16:43:35 +01:00
|
|
|
srv := NewServer(store.NewMemStore(), store.NewMemStore())
|
2018-08-09 20:56:49 +02:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2018-08-16 02:17:02 +02:00
|
|
|
blob := randBlob(1000)
|
2018-08-09 20:56:49 +02:00
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2018-08-16 02:17:02 +02:00
|
|
|
blob := randBlob(maxBlobSize)
|
2018-08-09 20:56:49 +02:00
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2018-08-16 02:17:02 +02:00
|
|
|
blob := randBlob(maxBlobSize + 1)
|
2018-08-09 20:56:49 +02:00
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2021-01-06 16:43:35 +01:00
|
|
|
srv := NewServer(store.NewMemStore(), store.NewMemStore())
|
2018-08-15 21:50:09 +02:00
|
|
|
srv.Timeout = testTimeout
|
2018-08-09 20:56:49 +02:00
|
|
|
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)
|
|
|
|
|
2018-08-16 02:17:02 +02:00
|
|
|
blob := randBlob(10)
|
2018-08-09 20:56:49 +02:00
|
|
|
|
|
|
|
err = c.SendBlob(blob)
|
|
|
|
t.Log(spew.Sdump(err))
|
|
|
|
if err != io.EOF {
|
|
|
|
t.Error("server should have timed out by now")
|
|
|
|
}
|
|
|
|
}
|
2018-08-16 02:17:02 +02:00
|
|
|
|
2019-05-01 21:39:14 +02:00
|
|
|
//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")
|
|
|
|
// }
|
|
|
|
//}
|
|
|
|
|
2018-08-16 02:17:02 +02:00
|
|
|
type mockPartialStore struct {
|
2020-10-22 19:49:02 +02:00
|
|
|
*store.MemStore
|
2018-08-16 02:17:02 +02:00
|
|
|
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()
|
|
|
|
}
|
|
|
|
|
2020-10-22 19:49:02 +02:00
|
|
|
st := store.BlobStore(&mockPartialStore{MemStore: store.NewMemStore(), missing: missing})
|
2018-08-16 02:17:02 +02:00
|
|
|
if _, ok := st.(neededBlobChecker); !ok {
|
|
|
|
t.Fatal("mock does not implement the relevant interface")
|
|
|
|
}
|
2018-08-16 03:19:38 +02:00
|
|
|
err = st.Put(sdHash, randBlob(10))
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-08-16 02:17:02 +02:00
|
|
|
|
2021-01-06 16:43:35 +01:00
|
|
|
srv := NewServer(st, st)
|
2018-08-16 02:17:02 +02:00
|
|
|
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
|
|
|
|
}
|