Commit 2ee10f7d authored by David Vorick's avatar David Vorick

write a test for uploading and downloading

parent c9e4fd95
cover
hostDir
hostdir
release
renterDownload
......
......@@ -20,7 +20,7 @@ install: fmt REBUILD
# development.
clean:
rm -rf hostdir release whitepaper.aux whitepaper.log whitepaper.pdf \
*.wallet *_test hostdir* siad/walletDir* siad/hostDir*
*.wallet *_test */*_test hostdir* siad/walletDir* siad/hostDir*
# test runs the short tests for Sia, and aims to always take less than 2
# seconds.
......@@ -31,7 +31,7 @@ test: clean fmt REBUILD
# with the race libraries enabled. test-long aims to be
# thorough.
test-long: clean fmt REBUILD
go test -v -race -tags=test -timeout=40s ./...
go test -v -race -tags=test -timeout=240s ./...
# cover runs the long tests and creats html files that show you which lines
# have been hit during testing and how many times each line has been hit.
......
......@@ -143,6 +143,9 @@ func (h *Host) addCollateral(txn consensus.Transaction, terms modules.ContractTe
if err != nil {
return
}
if collateral.Cmp(consensus.NewCurrency64(0)) == 0 {
return txn, txnID, nil
}
fundedTxn, err = h.wallet.FundTransaction(txnID, collateral)
if err != nil {
return
......
......@@ -5,6 +5,7 @@ import (
"io"
"net"
"os"
"path/filepath"
"time"
"github.com/NebulousLabs/Sia/consensus"
......@@ -35,7 +36,7 @@ func (h *Host) RetrieveFile(conn net.Conn) (err error) {
}
// Open the file.
file, err := os.Open(contractObligation.path)
file, err := os.Open(filepath.Join(h.hostDir, contractObligation.path))
if err != nil {
return
}
......@@ -45,7 +46,7 @@ func (h *Host) RetrieveFile(conn net.Conn) (err error) {
conn.SetDeadline(time.Now().Add(time.Duration(info.Size()) * 128 * time.Microsecond))
// Transmit the file.
_, err = io.Copy(conn, file)
_, err = io.CopyN(conn, file, int64(contractObligation.fileContract.FileSize))
if err != nil {
return
}
......
......@@ -176,6 +176,7 @@ func (r *Renter) negotiateContract(host modules.HostEntry, up modules.UploadPara
}
fcid = signedTxn.FileContractID(0)
contract = signedTxn.FileContracts[0]
// TODO: We don't actually watch the blockchain to make sure that the
// file contract made it.
......
......@@ -34,7 +34,7 @@ func downloadPiece(piece FilePiece, path string) error {
// Write the host's response into the file.
_, err = io.CopyN(file, conn, int64(piece.Contract.FileSize))
if err != nil {
os.Remove(path)
// os.Remove(path)
// r.hostDB.FlagHost(piece.Host.IPAddress)
return
}
......@@ -118,6 +118,7 @@ func (r *Renter) Download(nickname, filename string) error {
downloadErr := downloadPiece(piece, filename)
if downloadErr == nil {
return nil
} else {
}
// r.hostDB.FlagHost(piece.Host.IPAddress)
}
......@@ -132,7 +133,7 @@ func (r *Renter) Upload(up modules.UploadParams) error {
defer r.mu.Unlock()
// Check for a nickname conflict.
pieces, exists := r.files[up.Nickname]
_, exists := r.files[up.Nickname]
if exists {
return errors.New("file with that nickname already exists")
}
......@@ -142,7 +143,7 @@ func (r *Renter) Upload(up modules.UploadParams) error {
// more complex; once there is erasure coding we'll want to hit the minimum
// number of pieces plus some buffer before we decide that an upload is
// okay.
if r.hostDB.NumHosts() < 3 {
if r.hostDB.NumHosts() < 1 {
return errors.New("not enough hosts on the network to upload a file :( - maybe you need to upgrade your software")
}
......@@ -155,7 +156,7 @@ func (r *Renter) Upload(up modules.UploadParams) error {
// Upload a piece to every host on the network.
r.files[up.Nickname] = make([]FilePiece, up.Pieces)
for i := range pieces {
for i := range r.files[up.Nickname] {
// TODO: Eventually, each piece is likely to have different
// requirements. Erasure coding, index, etc. There will likely need to
// be a 'filePieceParameters' struct which is more complicated than the
......@@ -166,7 +167,7 @@ func (r *Renter) Upload(up modules.UploadParams) error {
// threadedUploadPiece will change the memory that the piece points to,
// which is useful because it means the file itself can be renamed but
// will still point to the same underlying pieces.
go r.threadedUploadPiece(up, &pieces[i])
go r.threadedUploadPiece(up, &r.files[up.Nickname][i])
}
return nil
......
......@@ -60,6 +60,10 @@ func (tp *TransactionPool) applyFileContracts(t consensus.Transaction, ut *uncon
}
}
_, exists := tp.newFileContracts[fc.Start]
if !exists {
tp.newFileContracts[fc.Start] = make(map[consensus.FileContractID]*unconfirmedTransaction)
}
tp.fileContracts[fcid] = fc
tp.newFileContracts[fc.Start][fcid] = ut
}
......
......@@ -35,10 +35,10 @@ func (d *daemon) initAPI(addr string) {
handleHTTPRequest(mux, "/consensus/status", d.statusHandler)
// Gateway API Calls
handleHTTPRequest(mux, "/gateway/add", d.peerAddHandler)
handleHTTPRequest(mux, "/gateway/remove", d.peerRemoveHandler)
handleHTTPRequest(mux, "/gateway/status", d.peerStatusHandler)
handleHTTPRequest(mux, "/gateway/synchronize", d.syncHandler)
handleHTTPRequest(mux, "/gateway/peer/add", d.peerAddHandler)
handleHTTPRequest(mux, "/gateway/peer/remove", d.peerRemoveHandler)
// Host API Calls
handleHTTPRequest(mux, "/host/config", d.hostConfigHandler)
......
......@@ -40,13 +40,13 @@ func TestPeering(t *testing.T) {
// Create to peers and add the first to the second.
peer1 := newDaemonTester(t)
peer2 := newDaemonTester(t)
peer1.callAPI("/gateway/add?addr=" + string(peer2.netAddress()))
peer1.callAPI("/gateway/peer/add?addr=" + string(peer2.netAddress()))
// Check that the first has the second as a peer.
var info modules.GatewayInfo
peer1.getAPI("/gateway/status", &info)
if len(info.Peers) != 1 || info.Peers[0] != peer2.netAddress() {
t.Fatal("/gateway/add did not add peer", peer2.netAddress())
t.Fatal("/gateway/peer/add did not add peer", peer2.netAddress())
}
// Create a third peer that bootstraps to the first peer and check that it
......
......@@ -109,10 +109,6 @@ func startEnvironment(*cobra.Command, []string) {
fmt.Println("Failed to create daemon:", err)
return
}
// join the network
if !config.Siacore.NoBootstrap {
go d.bootstrap()
}
// listen for API requests
err = d.listen()
if err != nil {
......
package main
import (
"fmt"
"time"
"github.com/NebulousLabs/Sia/network"
)
var (
// hard-coded addresses used when bootstrapping
BootstrapPeers = []network.Address{
"23.239.14.98:9988",
}
)
// bootstrap bootstraps to the network, downlading all of the blocks and
// establishing a peer list.
func (d *daemon) bootstrap() {
// Establish an initial peer list.
// TODO: add more bootstrap peers.
err := d.gateway.Bootstrap(BootstrapPeers[0])
if err != nil {
fmt.Println(`Warning: no peers responded to bootstrap request.
Add peers manually to enable bootstrapping.`)
// TODO: wait for new peers?
return
}
// Every 2 minutes, call Synchronize. In theory this shouldn't be
// necessary; it's here to improve robustness.
for {
go d.gateway.Synchronize()
time.Sleep(time.Minute * 2)
}
}
package main
import (
"os"
"testing"
"time"
"github.com/NebulousLabs/Sia/crypto"
)
// TestUploadAndDownload creates a network with a host and then uploads a file
// from the renter to the host, and then downloads it.
func TestUploadAndDownload(t *testing.T) {
if testing.Short() {
t.Skip()
}
// Create a daemon and add a host to the network.
dt := newDaemonTester(t)
dt.announceHost()
for dt.hostdb.NumHosts() == 0 {
time.Sleep(time.Millisecond)
}
// Upload to the host.
dt.callAPI("/renter/uploadpath?pieces=1&filename=api.go&nickname=first&pieces=1")
// Wait 65 seconds for the upload to finish - this is necessary due to the
// fact that zero-conf transactions aren't actually propagated properly.
time.Sleep(time.Second * 65)
rentInfo := dt.renter.Info()
if len(rentInfo.Files) != 1 {
t.Error("file is not uploaded")
}
// Try to download the file.
dt.callAPI("/renter/download?filename=renterTestDL_test&nickname=first")
time.Sleep(time.Second * 15)
// Check that the downloaded file is equal to the uploaded file.
upFile, err := os.Open("api.go")
if err != nil {
t.Fatal(err)
}
defer upFile.Close()
downFile, err := os.Open("renterTestDL_test")
if err != nil {
t.Fatal(err)
}
defer upFile.Close()
upRoot, err := crypto.ReaderMerkleRoot(upFile)
if err != nil {
t.Fatal(err)
}
downRoot, err := crypto.ReaderMerkleRoot(downFile)
if err != nil {
t.Fatal(err)
}
if upRoot != downRoot {
t.Error("uploaded and downloaded file have a hash mismatch")
}
}
package main
/*
import (
"testing"
)
// sendManyTransactions repeatedly sends transactions, attempting to trigger a
// bug where transactions randomly fail to verify. Though this bug has since
// been found and fixed, the tests have been left behind.
func sendManyTransactions(t *testing.T, c *Core) {
if testing.Short() {
return
}
// Unfortunately, only 1 transaction per block can be sent, because the
// wallet doesn't work with txn pool changes yet.
blocks := 12
for i := 0; i < blocks; i++ {
address, _, err := c.wallet.CoinAddress()
if err != nil {
return
}
// Can only send as many transactions as we have inputs. Because we
// send things to ourselves and then get the refund as well, we get a
// new transaction we send, but the delay is one block.
for j := 0; j < i; j++ {
_, err := c.wallet.SpendCoins(123, address)
if err != nil {
t.Error(err)
}
}
// mineSingleBlock(t, c)
}
}
*/
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment