swarm/testutil: Testing framework demo

This commit is contained in:
Javier Peletier 2018-12-18 00:34:34 +01:00
parent 472c23a801
commit a5af8afd89
13 changed files with 256 additions and 397 deletions

View file

@ -17,12 +17,12 @@
package http
import (
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
"testing"
"github.com/ethereum/go-ethereum/swarm/testutil"
"github.com/ethereum/go-ethereum/swarm/api"
"github.com/ethereum/go-ethereum/swarm/storage"
"github.com/ethereum/go-ethereum/swarm/storage/feed"
@ -32,33 +32,21 @@ type TestServer interface {
ServeHTTP(http.ResponseWriter, *http.Request)
}
func NewTestSwarmServer(t *testing.T, serverFunc func(*api.API) TestServer, resolver api.Resolver) *TestSwarmServer {
dir, err := ioutil.TempDir("", "swarm-storage-test")
if err != nil {
t.Fatal(err)
}
func NewTestSwarmServer(tx *testing.T, serverFunc func(*api.API) TestServer, resolver api.Resolver) *TestSwarmServer {
// hacked this function for the testing framework demo. Disregard changes here.
t := testutil.BeginTest(tx, false)
dir := t.Services.NewTempDir()
storeparams := storage.NewDefaultLocalStoreParams()
storeparams.DbCapacity = 5000000
storeparams.CacheCapacity = 5000
storeparams.Init(dir)
localStore, err := storage.NewLocalStore(storeparams, nil)
if err != nil {
os.RemoveAll(dir)
t.Fatal(err)
}
t.Ok(err)
fileStore := storage.NewFileStore(localStore, storage.NewFileStoreParams())
// Swarm feeds test setup
feedsDir, err := ioutil.TempDir("", "swarm-feeds-test")
if err != nil {
t.Fatal(err)
}
rhparams := &feed.HandlerParams{}
rh, err := feed.NewTestHandler(feedsDir, rhparams)
if err != nil {
t.Fatal(err)
}
rh := feed.NewTestHandler(t, "")
a := api.NewAPI(fileStore, resolver, rh.Handler, nil)
srv := httptest.NewServer(serverFunc(a))
@ -70,8 +58,7 @@ func NewTestSwarmServer(t *testing.T, serverFunc func(*api.API) TestServer, reso
cleanup: func() {
srv.Close()
rh.Close()
os.RemoveAll(dir)
os.RemoveAll(feedsDir)
t.FinishTest()
},
CurrentTime: 42,
}

View file

@ -17,11 +17,9 @@
package feed
import (
"bytes"
"context"
"flag"
"fmt"
"io/ioutil"
"os"
"testing"
"time"
@ -31,6 +29,7 @@ import (
"github.com/ethereum/go-ethereum/swarm/chunk"
"github.com/ethereum/go-ethereum/swarm/storage"
"github.com/ethereum/go-ethereum/swarm/storage/feed/lookup"
"github.com/ethereum/go-ethereum/swarm/testutil"
)
var (
@ -71,7 +70,9 @@ func (f *fakeTimeProvider) Now() Timestamp {
}
// make updates and retrieve them based on periods and versions
func TestFeedsHandler(t *testing.T) {
func TestFeedsHandler(tx *testing.T) {
t := testutil.BeginTest(tx, false) // set to true to generate results
defer t.FinishTest()
// make fake timeProvider
clock := &fakeTimeProvider{
@ -80,12 +81,7 @@ func TestFeedsHandler(t *testing.T) {
// signer containing private key
signer := newAliceSigner()
feedsHandler, datadir, teardownTest, err := setupTest(clock, signer)
if err != nil {
t.Fatal(err)
}
defer teardownTest()
feedsHandler := setupTest(t, clock)
// create a new feed
ctx, cancel := context.WithCancel(context.Background())
@ -109,86 +105,68 @@ func TestFeedsHandler(t *testing.T) {
chunkAddress := make(map[string]storage.Address)
data := []byte(updates[0])
request.SetData(data)
if err := request.Sign(signer); err != nil {
t.Fatal(err)
}
err := request.Sign(signer)
t.Ok(err)
chunkAddress[updates[0]], err = feedsHandler.Update(ctx, request)
if err != nil {
t.Fatal(err)
}
t.Ok(err)
// move the clock ahead 21 seconds
clock.FastForward(21) // t=4221
request, err = feedsHandler.NewRequest(ctx, &request.Feed) // this timestamps the update at t = 4221
if err != nil {
t.Fatal(err)
}
if request.Epoch.Base() != 0 || request.Epoch.Level != lookup.HighestLevel-1 {
t.Fatalf("Suggested epoch BaseTime should be 0 and Epoch level should be %d", lookup.HighestLevel-1)
}
t.Ok(err)
t.Assert(request.Epoch.Base() == 0 && request.Epoch.Level == lookup.HighestLevel-1, "Suggested epoch BaseTime should be 0 and Epoch level should be %d", lookup.HighestLevel-1)
request.Epoch.Level = lookup.HighestLevel // force level 25 instead of 24 to make it fail
data = []byte(updates[1])
request.SetData(data)
if err := request.Sign(signer); err != nil {
t.Fatal(err)
}
err = request.Sign(signer)
t.Ok(err)
chunkAddress[updates[1]], err = feedsHandler.Update(ctx, request)
if err == nil {
t.Fatal("Expected update to fail since an update in this epoch already exists")
}
t.MustFail(err, "Expected update to fail since an update in this epoch already exists")
// move the clock ahead 21 seconds
clock.FastForward(21) // t=4242
request, err = feedsHandler.NewRequest(ctx, &request.Feed)
if err != nil {
t.Fatal(err)
}
t.Ok(err)
request.SetData(data)
if err := request.Sign(signer); err != nil {
t.Fatal(err)
}
err = request.Sign(signer)
t.Ok(err)
chunkAddress[updates[1]], err = feedsHandler.Update(ctx, request)
if err != nil {
t.Fatal(err)
}
t.Ok(err)
// move the clock ahead 42 seconds
clock.FastForward(42) // t=4284
request, err = feedsHandler.NewRequest(ctx, &request.Feed)
if err != nil {
t.Fatal(err)
}
t.Ok(err)
data = []byte(updates[2])
request.SetData(data)
if err := request.Sign(signer); err != nil {
t.Fatal(err)
}
err = request.Sign(signer)
t.Ok(err)
chunkAddress[updates[2]], err = feedsHandler.Update(ctx, request)
if err != nil {
t.Fatal(err)
}
t.Ok(err)
// move the clock ahead 1 second
clock.FastForward(1) // t=4285
request, err = feedsHandler.NewRequest(ctx, &request.Feed)
if err != nil {
t.Fatal(err)
}
if request.Epoch.Base() != 0 || request.Epoch.Level != 22 {
t.Fatalf("Expected epoch base time to be %d, got %d. Expected epoch level to be %d, got %d", 0, request.Epoch.Base(), 22, request.Epoch.Level)
}
t.Ok(err)
t.Assert(request.Epoch.Base() == 0 && request.Epoch.Level == 22, "Expected epoch base time to be %d, got %d. Expected epoch level to be %d, got %d", 0, request.Epoch.Base(), 22, request.Epoch.Level)
data = []byte(updates[3])
request.SetData(data)
if err := request.Sign(signer); err != nil {
t.Fatal(err)
}
err = request.Sign(signer)
t.Ok(err)
chunkAddress[updates[3]], err = feedsHandler.Update(ctx, request)
if err != nil {
t.Fatal(err)
}
t.Ok(err)
time.Sleep(time.Second)
feedsHandler.Close()
@ -196,47 +174,29 @@ func TestFeedsHandler(t *testing.T) {
// check we can retrieve the updates after close
clock.FastForward(2000) // t=6285
feedParams := &HandlerParams{}
feedsHandler2, err := NewTestHandler(datadir, feedParams)
if err != nil {
t.Fatal(err)
}
feedsHandler2 := NewTestHandler(t, feedsHandler.dataDir)
t.Ok(err)
update2, err := feedsHandler2.Lookup(ctx, NewQueryLatest(&request.Feed, lookup.NoClue))
if err != nil {
t.Fatal(err)
}
t.Ok(err)
// last update should be "clyde"
if !bytes.Equal(update2.data, []byte(updates[len(updates)-1])) {
t.Fatalf("feed update data was %v, expected %v", string(update2.data), updates[len(updates)-1])
}
if update2.Level != 22 {
t.Fatalf("feed update epoch level was %d, expected 22", update2.Level)
}
if update2.Base() != 0 {
t.Fatalf("feed update epoch base time was %d, expected 0", update2.Base())
}
t.Equals([]byte(updates[len(updates)-1]), update2.data)
t.Assert(update2.Level == 22, "feed update epoch level was %d, expected 22", update2.Level)
t.Assert(update2.Base() == 0, "feed update epoch base time was %d, expected 0", update2.Base())
log.Debug("Latest lookup", "epoch base time", update2.Base(), "epoch level", update2.Level, "data", update2.data)
// specific point in time
update, err := feedsHandler2.Lookup(ctx, NewQuery(&request.Feed, 4284, lookup.NoClue))
if err != nil {
t.Fatal(err)
}
// check data
if !bytes.Equal(update.data, []byte(updates[2])) {
t.Fatalf("feed update data (historical) was %v, expected %v", string(update2.data), updates[2])
}
t.Ok(err)
t.Equals([]byte(updates[2]), update.data)
log.Debug("Historical lookup", "epoch base time", update2.Base(), "epoch level", update2.Level, "data", update2.data)
// beyond the first should yield an error
update, err = feedsHandler2.Lookup(ctx, NewQuery(&request.Feed, startTime.Time-1, lookup.NoClue))
if err == nil {
t.Fatalf("expected previous to fail, returned epoch %s data %v", update.Epoch.String(), update.data)
}
t.MustFail(err, "expected previous to fail")
}
const Day = 60 * 60 * 24
@ -247,7 +207,9 @@ func generateData(x uint64) []byte {
return []byte(fmt.Sprintf("%d", x))
}
func TestSparseUpdates(t *testing.T) {
func TestSparseUpdates(tx *testing.T) {
t := testutil.BeginTest(tx, false) // set to true to generate results
defer t.FinishTest()
// make fake timeProvider
timeProvider := &fakeTimeProvider{
@ -256,13 +218,7 @@ func TestSparseUpdates(t *testing.T) {
// signer containing private key
signer := newAliceSigner()
rh, datadir, teardownTest, err := setupTest(timeProvider, signer)
if err != nil {
t.Fatal(err)
}
defer teardownTest()
defer os.RemoveAll(datadir)
rh := setupTest(t, timeProvider)
// create a new feed
ctx, cancel := context.WithCancel(context.Background())
@ -281,33 +237,24 @@ func TestSparseUpdates(t *testing.T) {
request := NewFirstRequest(fd.Topic)
request.Epoch = lookup.GetNextEpoch(epoch, T)
request.data = generateData(T) // this generates some data that depends on T, so we can check later
request.Sign(signer)
if err != nil {
t.Fatal(err)
}
err := request.Sign(signer)
t.Ok(err)
_, err = rh.Update(ctx, request)
t.Ok(err)
if _, err := rh.Update(ctx, request); err != nil {
t.Fatal(err)
}
epoch = request.Epoch
lastUpdateTime = T
}
query := NewQuery(&fd, today, lookup.NoClue)
_, err = rh.Lookup(ctx, query)
if err != nil {
t.Fatal(err)
}
_, err := rh.Lookup(ctx, query)
t.Ok(err)
_, content, err := rh.GetContent(&fd)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(generateData(lastUpdateTime), content) {
t.Fatalf("Expected to recover last written value %d, got %s", lastUpdateTime, string(content))
}
t.Ok(err)
t.Equals(generateData(lastUpdateTime), content)
// lookup the closest update to 35*Year + 6* Month (~ June 2005):
// it should find the update we put on 35*Year, since we were updating every 5 years.
@ -315,21 +262,16 @@ func TestSparseUpdates(t *testing.T) {
query.TimeLimit = 35*Year + 6*Month
_, err = rh.Lookup(ctx, query)
if err != nil {
t.Fatal(err)
}
t.Ok(err)
_, content, err = rh.GetContent(&fd)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(generateData(35*Year), content) {
t.Fatalf("Expected to recover %d, got %s", 35*Year, string(content))
}
t.Ok(err)
t.Equals(generateData(35*Year), content)
}
func TestValidator(t *testing.T) {
func TestValidator(tx *testing.T) {
t := testutil.BeginTest(tx, false) // set to true to generate results
defer t.FinishTest()
// make fake timeProvider
timeProvider := &fakeTimeProvider{
@ -338,13 +280,8 @@ func TestValidator(t *testing.T) {
// signer containing private key. Alice will be the good girl
signer := newAliceSigner()
// set up sim timeProvider
rh, _, teardownTest, err := setupTest(timeProvider, signer)
if err != nil {
t.Fatal(err)
}
defer teardownTest()
rh := setupTest(t, timeProvider)
// create new feed
topic, _ := NewTopic(subtopicName, nil)
@ -357,33 +294,27 @@ func TestValidator(t *testing.T) {
// chunk with address
data := []byte("foo")
mr.SetData(data)
if err := mr.Sign(signer); err != nil {
t.Fatalf("sign fail: %v", err)
}
err := mr.Sign(signer)
t.Ok(err)
chunk, err := mr.toChunk()
if err != nil {
t.Fatal(err)
}
if !rh.Validate(chunk) {
t.Fatal("Chunk validator fail on update chunk")
}
t.Ok(err)
t.Assert(rh.Validate(chunk), "Chunk validator fail on update chunk")
address := chunk.Address()
// mess with the address
address[0] = 11
address[15] = 99
if rh.Validate(storage.NewChunk(address, chunk.Data())) {
t.Fatal("Expected Validate to fail with false chunk address")
}
t.Assert(!rh.Validate(storage.NewChunk(address, chunk.Data())), "Expected Validate to fail with false chunk address")
}
// tests that the content address validator correctly checks the data
// tests that feed update chunks are passed through content address validator
// there is some redundancy in this test as it also tests content addressed chunks,
// which should be evaluated as invalid chunks by this validator
func TestValidatorInStore(t *testing.T) {
func TestValidatorInStore(tx *testing.T) {
t := testutil.BeginTest(tx, false) // set to true to generate results
defer t.FinishTest()
// make fake timeProvider
TimestampProvider = &fakeTimeProvider{
@ -392,24 +323,16 @@ func TestValidatorInStore(t *testing.T) {
// signer containing private key
signer := newAliceSigner()
// set up localstore
datadir, err := ioutil.TempDir("", "storage-testfeedsvalidator")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(datadir)
datadir := t.Services.NewTempDir()
handlerParams := storage.NewDefaultLocalStoreParams()
handlerParams.Init(datadir)
store, err := storage.NewLocalStore(handlerParams, nil)
if err != nil {
t.Fatal(err)
}
t.Ok(err)
// set up Swarm feeds handler and add is as a validator to the localstore
fhParams := &HandlerParams{}
fh := NewHandler(fhParams)
fh := NewHandler(&HandlerParams{})
store.Validators = append(store.Validators, fh)
// create content addressed chunks, one good, one faulty
@ -439,55 +362,28 @@ func TestValidatorInStore(t *testing.T) {
r.Update.ID = id
r.data = data
r.Sign(signer)
err = r.Sign(signer)
t.Ok(err)
uglyChunk, err := r.toChunk()
if err != nil {
t.Fatal(err)
}
t.Ok(err)
// put the chunks in the store and check their error status
err = store.Put(context.Background(), goodChunk)
if err == nil {
t.Fatal("expected error on good content address chunk with feed update validator only, but got nil")
}
t.MustFail(err, "expected error on good content address chunk with feed update validator only, but got nil")
err = store.Put(context.Background(), badChunk)
if err == nil {
t.Fatal("expected error on bad content address chunk with feed update validator only, but got nil")
}
err = store.Put(context.Background(), uglyChunk)
if err != nil {
t.Fatalf("expected no error on feed update chunk with feed update validator only, but got: %s", err)
}
t.MustFail(err, "expected error on bad content address chunk with feed update validator only, but got nil")
err = store.Put(context.Background(), uglyChunk) // feed update chunk with feed update validator only
t.Ok(err)
}
// create rpc and feeds Handler
func setupTest(timeProvider timestampProvider, signer Signer) (fh *TestHandler, datadir string, teardown func(), err error) {
var fsClean func()
var rpcClean func()
cleanF = func() {
if fsClean != nil {
fsClean()
}
if rpcClean != nil {
rpcClean()
}
}
// temp datadir
datadir, err = ioutil.TempDir("", "fh")
if err != nil {
return nil, "", nil, err
}
fsClean = func() {
os.RemoveAll(datadir)
}
func setupTest(t *testutil.SwarmTestTools, timeProvider timestampProvider) *TestHandler {
TimestampProvider = timeProvider
fhParams := &HandlerParams{}
fh, err = NewTestHandler(datadir, fhParams)
return fh, datadir, cleanF, err
fh := NewTestHandler(t, "")
return fh
}
func newAliceSigner() *GenericSigner {

View file

@ -17,38 +17,27 @@
package feed
import (
"bytes"
"encoding/binary"
"encoding/json"
"fmt"
"reflect"
"testing"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/swarm/storage"
"github.com/ethereum/go-ethereum/swarm/storage/feed/lookup"
"github.com/ethereum/go-ethereum/swarm/testutil"
)
func areEqualJSON(s1, s2 string) (bool, error) {
//credit for the trick: turtlemonvh https://gist.github.com/turtlemonvh/e4f7404e28387fadb8ad275a99596f67
var o1 interface{}
var o2 interface{}
err := json.Unmarshal([]byte(s1), &o1)
if err != nil {
return false, fmt.Errorf("Error mashalling string 1 :: %s", err.Error())
}
err = json.Unmarshal([]byte(s2), &o2)
if err != nil {
return false, fmt.Errorf("Error mashalling string 2 :: %s", err.Error())
}
return reflect.DeepEqual(o1, o2), nil
}
// TestEncodingDecodingUpdateRequests ensures that requests are serialized properly
// while also checking cryptographically that only the owner of a feed can update it.
func TestEncodingDecodingUpdateRequests(t *testing.T) {
func TestEncodingDecodingUpdateRequests(tx *testing.T) {
t := testutil.BeginTest(tx, false) // set to true to generate results
defer t.FinishTest()
TimestampProvider = &fakeTimeProvider{
currentTime: startTime.Time, // clock starts at t=4200
}
charlie := newCharlieSigner() //Charlie
bob := newBobSigner() //Bob
@ -58,28 +47,12 @@ func TestEncodingDecodingUpdateRequests(t *testing.T) {
firstRequest := NewFirstRequest(topic)
firstRequest.User = charlie.Address()
// We now encode the create message to simulate we send it over the wire
messageRawData, err := firstRequest.MarshalJSON()
if err != nil {
t.Fatalf("Error encoding first feed update request: %s", err)
}
t.TestJSONMarshaller("firstrequest.json", firstRequest)
// ... the message arrives and is decoded...
var recoveredFirstRequest Request
if err := recoveredFirstRequest.UnmarshalJSON(messageRawData); err != nil {
t.Fatalf("Error decoding first feed update request: %s", err)
}
// ... but verification should fail because it is not signed!
if err := recoveredFirstRequest.Verify(); err == nil {
t.Fatal("Expected Verify to fail since the message is not signed")
}
// We now assume that the feed ypdate was created and propagated.
const expectedSignature = "0x7235b27a68372ddebcf78eba48543fa460864b0b0e99cb533fcd3664820e603312d29426dd00fb39628f5299480a69bf6e462838d78de49ce0704c754c9deb2601"
const expectedJSON = `{"feed":{"topic":"0x6120676f6f6420746f706963206e616d65000000000000000000000000000000","user":"0x876a8936a7cd0b79ef0735ad0896c1afe278781c"},"epoch":{"time":1000,"level":1},"protocolVersion":0,"data":"0x5468697320686f75722773207570646174653a20537761726d2039392e3020686173206265656e2072656c656173656421"}`
// but verification should fail because it is not signed!
t.MustFail(firstRequest.Verify(), "Expected Verify to fail since the message is not signed")
// We now assume that the feed update was created and propagated.
//Put together an unsigned update request that we will serialize to send it to the signer.
data := []byte("This hour's update: Swarm 99.0 has been released!")
request := &Request{
@ -95,96 +68,74 @@ func TestEncodingDecodingUpdateRequests(t *testing.T) {
},
}
messageRawData, err = request.MarshalJSON()
if err != nil {
t.Fatalf("Error encoding update request: %s", err)
}
equalJSON, err := areEqualJSON(string(messageRawData), expectedJSON)
if err != nil {
t.Fatalf("Error decoding update request JSON: %s", err)
}
if !equalJSON {
t.Fatalf("Received a different JSON message. Expected %s, got %s", expectedJSON, string(messageRawData))
}
messageRawData, err := request.MarshalJSON()
t.Ok(err)
t.JSONBytesEqualsFile("secondrequest.json", messageRawData)
// now the encoded message messageRawData is sent over the wire and arrives to the signer
//Attempt to extract an UpdateRequest out of the encoded message
var recoveredRequest Request
if err := recoveredRequest.UnmarshalJSON(messageRawData); err != nil {
t.Fatalf("Error decoding update request: %s", err)
}
err = recoveredRequest.UnmarshalJSON(messageRawData)
t.Ok(err)
//sign the request and see if it matches our predefined signature above.
if err := recoveredRequest.Sign(charlie); err != nil {
t.Fatalf("Error signing request: %s", err)
}
compareByteSliceToExpectedHex(t, "signature", recoveredRequest.Signature[:], expectedSignature)
err = recoveredRequest.Sign(charlie)
t.Ok(err)
t.EqualsKey("signature", hexutil.Encode(recoveredRequest.Signature[:]))
// mess with the signature and see what happens. To alter the signature, we briefly decode it as JSON
// to alter the signature field.
var j updateRequestJSON
if err := json.Unmarshal([]byte(expectedJSON), &j); err != nil {
t.Fatal("Error unmarshalling test json, check expectedJSON constant")
}
err = json.Unmarshal([]byte(messageRawData), &j)
t.Ok(err)
j.Signature = "Certainly not a signature"
corruptMessage, _ := json.Marshal(j) // encode the message with the bad signature
var corruptRequest Request
if err = corruptRequest.UnmarshalJSON(corruptMessage); err == nil {
t.Fatal("Expected DecodeUpdateRequest to fail when trying to interpret a corrupt message with an invalid signature")
}
err = corruptRequest.UnmarshalJSON(corruptMessage)
t.MustFail(err, "Expected DecodeUpdateRequest to fail when trying to interpret a corrupt message with an invalid signature")
// Now imagine Bob wants to create an update of his own about the same feed,
// signing a message with his private key
if err := request.Sign(bob); err != nil {
t.Fatalf("Error signing: %s", err)
}
err = request.Sign(bob)
t.Ok(err)
// Now Bob encodes the message to send it over the wire...
messageRawData, err = request.MarshalJSON()
if err != nil {
t.Fatalf("Error encoding message:%s", err)
}
t.Ok(err)
// ... the message arrives to our Swarm node and it is decoded.
recoveredRequest = Request{}
if err := recoveredRequest.UnmarshalJSON(messageRawData); err != nil {
t.Fatalf("Error decoding message:%s", err)
}
err = recoveredRequest.UnmarshalJSON(messageRawData)
t.Ok(err)
// Before checking what happened with Bob's update, let's see what would happen if we mess
// with the signature big time to see if Verify catches it
savedSignature := *recoveredRequest.Signature // save the signature for later
binary.LittleEndian.PutUint64(recoveredRequest.Signature[5:], 556845463424) // write some random data to break the signature
if err = recoveredRequest.Verify(); err == nil {
t.Fatal("Expected Verify to fail on corrupt signature")
}
err = recoveredRequest.Verify()
t.MustFail(err, "Expected Verify to fail on corrupt signature")
// restore the Bob's signature from corruption
*recoveredRequest.Signature = savedSignature
// Now the signature is not corrupt
if err = recoveredRequest.Verify(); err != nil {
t.Fatal(err)
}
err = recoveredRequest.Verify()
t.Ok(err)
// Reuse object and sign with our friend Charlie's private key
if err := recoveredRequest.Sign(charlie); err != nil {
t.Fatalf("Error signing with the correct private key: %s", err)
}
err = recoveredRequest.Sign(charlie)
t.Ok(err)
// And now, Verify should work since this update now belongs to Charlie
if err = recoveredRequest.Verify(); err != nil {
t.Fatalf("Error verifying that Charlie, can sign a reused request object:%s", err)
}
err = recoveredRequest.Verify()
t.Ok(err)
// mess with the lookup key to make sure Verify fails:
recoveredRequest.Time = 77999 // this will alter the lookup key
if err = recoveredRequest.Verify(); err == nil {
t.Fatalf("Expected Verify to fail since the lookup key has been altered")
}
err = recoveredRequest.Verify()
t.MustFail(err, "Expected Verify to fail since the lookup key has been altered")
}
func getTestRequest() *Request {
@ -233,28 +184,18 @@ func TestUpdateChunkSerializationErrorChecking(t *testing.T) {
}
// check that signature address matches update signer address
func TestReverse(t *testing.T) {
func TestReverse(tx *testing.T) {
t := testutil.BeginTest(tx, false) // set to true to generate results
defer t.FinishTest()
epoch := lookup.Epoch{
Time: 7888,
Level: 6,
}
// make fake timeProvider
timeProvider := &fakeTimeProvider{
currentTime: startTime.Time,
}
// signer containing private key
signer := newAliceSigner()
// set up rpc and create feeds handler
_, _, teardownTest, err := setupTest(timeProvider, signer)
if err != nil {
t.Fatal(err)
}
defer teardownTest()
topic, _ := NewTopic("Cervantes quotes", nil)
fd := Feed{
Topic: topic,
@ -271,42 +212,30 @@ func TestReverse(t *testing.T) {
// generate a chunk key for this request
key := request.Addr()
if err = request.Sign(signer); err != nil {
t.Fatal(err)
}
err := request.Sign(signer)
t.Ok(err)
chunk, err := request.toChunk()
if err != nil {
t.Fatal(err)
}
t.Ok(err)
// check that we can recover the owner account from the update chunk's signature
var checkUpdate Request
if err := checkUpdate.fromChunk(chunk); err != nil {
t.Fatal(err)
}
err = checkUpdate.fromChunk(chunk)
t.Ok(err)
checkdigest, err := checkUpdate.GetDigest()
if err != nil {
t.Fatal(err)
}
recoveredAddr, err := getUserAddr(checkdigest, *checkUpdate.Signature)
if err != nil {
t.Fatalf("Retrieve address from signature fail: %v", err)
}
t.Ok(err)
recoveredAddr, err := getUserAddr(checkdigest, *checkUpdate.Signature) //Retrieve address from signature
t.Ok(err)
originalAddr := crypto.PubkeyToAddress(signer.PrivKey.PublicKey)
// check that the metadata retrieved from the chunk matches what we gave it
if recoveredAddr != originalAddr {
t.Fatalf("addresses dont match: %x != %x", originalAddr, recoveredAddr)
}
t.Assert(recoveredAddr == originalAddr, "addresses dont match: %x != %x", originalAddr, recoveredAddr)
t.Equals(chunk.Address()[:], key[:])
if !bytes.Equal(key[:], chunk.Address()[:]) {
t.Fatalf("Expected chunk key '%x', was '%x'", key, chunk.Address())
}
if epoch != checkUpdate.Epoch {
t.Fatalf("Expected epoch to be '%s', was '%s'", epoch.String(), checkUpdate.Epoch.String())
}
if !bytes.Equal(data, checkUpdate.data) {
t.Fatalf("Expected data '%x', was '%x'", data, checkUpdate.data)
}
t.Assert(epoch == checkUpdate.Epoch, "Expected epoch to be '%s', was '%s'", epoch.String(), checkUpdate.Epoch.String())
t.Equals(checkUpdate.data, data)
}

View file

@ -0,0 +1,11 @@
{
"feed": {
"topic": "0x6120676f6f6420746f706963206e616d65000000000000000000000000000000",
"user": "0x876a8936a7cd0b79ef0735ad0896c1afe278781c"
},
"epoch": {
"time": 4200,
"level": 25
},
"protocolVersion": 0
}

View file

@ -0,0 +1,3 @@
{
"signature": "0x7235b27a68372ddebcf78eba48543fa460864b0b0e99cb533fcd3664820e603312d29426dd00fb39628f5299480a69bf6e462838d78de49ce0704c754c9deb2601"
}

View file

@ -0,0 +1,12 @@
{
"feed": {
"topic": "0x6120676f6f6420746f706963206e616d65000000000000000000000000000000",
"user": "0x876a8936a7cd0b79ef0735ad0896c1afe278781c"
},
"epoch": {
"time": 1000,
"level": 1
},
"protocolVersion": 0,
"data": "0x5468697320686f75722773207570646174653a20537761726d2039392e3020686173206265656e2072656c656173656421"
}

View file

@ -0,0 +1,3 @@
{
"hex": "0xdfa89c750e3108f9c2aeef0123456789abcdef0123456789abcdef0123456789"
}

View file

@ -0,0 +1 @@
"0xdfa89c750e3108f9c2aeef0123456789abcdef0123456789abcdef0123456789"

View file

@ -18,20 +18,16 @@ package feed
import (
"context"
"fmt"
"path/filepath"
"sync"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/swarm/storage"
)
const (
testDbDirName = "feeds"
"github.com/ethereum/go-ethereum/swarm/testutil"
)
type TestHandler struct {
*Handler
dataDir string
}
func (t *TestHandler) Close() {
@ -50,22 +46,24 @@ func newFakeNetFetcher(context.Context, storage.Address, *sync.Map) storage.NetF
}
// NewTestHandler creates Handler object to be used for testing purposes.
func NewTestHandler(datadir string, params *HandlerParams) (*TestHandler, error) {
path := filepath.Join(datadir, testDbDirName)
fh := NewHandler(params)
func NewTestHandler(t *testutil.SwarmTestTools, path string) *TestHandler {
if path == "" {
path = t.Services.NewTempDir()
}
fh := NewHandler(&HandlerParams{})
localstoreparams := storage.NewDefaultLocalStoreParams()
localstoreparams.Init(path)
localStore, err := storage.NewLocalStore(localstoreparams, nil)
if err != nil {
return nil, fmt.Errorf("localstore create fail, path %s: %v", path, err)
}
t.Ok(err)
localStore.Validators = append(localStore.Validators, storage.NewContentAddressValidator(storage.MakeHashFunc(feedsHashAlgorithm)))
localStore.Validators = append(localStore.Validators, fh)
netStore, err := storage.NewNetStore(localStore, nil)
if err != nil {
return nil, err
}
t.Ok(err)
netStore.NewNetFetcherFunc = newFakeNetFetcher
fh.SetStore(netStore)
return &TestHandler{fh}, nil
th := &TestHandler{
Handler: fh,
dataDir: path,
}
return th
}

View file

@ -4,47 +4,23 @@ import (
"testing"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/swarm/testutil"
)
func TestTopic(t *testing.T) {
func TestTopic(tx *testing.T) {
t := testutil.BeginTest(tx, false) // set to true to generate results
defer t.FinishTest()
related, _ := hexutil.Decode("0xabcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789")
topicName := "test-topic"
topic, _ := NewTopic(topicName, related)
hex := topic.Hex()
expectedHex := "0xdfa89c750e3108f9c2aeef0123456789abcdef0123456789abcdef0123456789"
if hex != expectedHex {
t.Fatalf("Expected %s, got %s", expectedHex, hex)
}
t.EqualsKey("hex", hex)
var topic2 Topic
topic2.FromHex(hex)
if topic2 != topic {
t.Fatal("Expected recovered topic to be equal to original one")
}
if topic2.Name(related) != topicName {
t.Fatal("Retrieved name does not match")
}
bytes, err := topic2.MarshalJSON()
if err != nil {
t.Fatal(err)
}
expectedJSON := `"0xdfa89c750e3108f9c2aeef0123456789abcdef0123456789abcdef0123456789"`
equal, err := areEqualJSON(expectedJSON, string(bytes))
if err != nil {
t.Fatal(err)
}
if !equal {
t.Fatalf("Expected JSON to be %s, got %s", expectedJSON, string(bytes))
}
err = topic2.UnmarshalJSON(bytes)
if err != nil {
t.Fatal(err)
}
if topic2 != topic {
t.Fatal("Expected recovered topic to be equal to original one")
}
t.Equals(topic, topic2)
t.Equals(topicName, topic2.Name(related))
t.TestJSONMarshaller("topic.json", &topic2)
}

View file

@ -26,6 +26,8 @@ import (
"testing"
)
//TODO: refactor these as TestServices
// TempFileWithContent is a helper function that creates a temp file that contains the following string content then closes the file handle
// it returns the complete file path
func TempFileWithContent(t *testing.T, content string) string {

View file

@ -0,0 +1,20 @@
package testutil
import (
"github.com/epiclabs-io/ut"
)
// SwarmTestServices groups all third-party dependencies to provide easy instantiation
// and cleanup of these. By default, it provides temporary files and directories
type swarmTestServices struct {
tt *SwarmTestTools
*ut.FileServices
}
// Instantiate Test services
func newSwarmTestServices(tt *SwarmTestTools) *swarmTestServices {
return &swarmTestServices{
tt: tt,
FileServices: ut.NewFileServices(tt.TestTools),
}
}

View file

@ -0,0 +1,21 @@
package testutil
import (
"testing"
"github.com/epiclabs-io/ut"
)
// SwarmTestTools are Swarm-specific test tools
type SwarmTestTools struct {
*ut.TestTools
Services *swarmTestServices
}
// BeginTest returns a project-specific test toolbox
func BeginTest(tb testing.TB, generateResults bool) *SwarmTestTools {
ett := new(SwarmTestTools)
ett.TestTools = ut.BeginTest(tb, generateResults)
ett.Services = newSwarmTestServices(ett)
return ett
}