From: Matt Joiner Date: Wed, 8 Nov 2017 08:31:10 +0000 (+1100) Subject: Add a test for behaviour after getting metadata_size and before GotInfo X-Git-Tag: v1.0.0~335 X-Git-Url: http://www.git.stargrave.org/?a=commitdiff_plain;h=3aa1e8f3ef260a617e262aa52af45919e01edc86;p=btrtrc.git Add a test for behaviour after getting metadata_size and before GotInfo #208 --- diff --git a/client.go b/client.go index ee2c8a3a..6a8b6216 100644 --- a/client.go +++ b/client.go @@ -1031,6 +1031,9 @@ func (cl *Client) newTorrent(ih metainfo.Hash, specStorage storage.ClientImpl) ( networkingEnabled: true, requestStrategy: 2, + metadataChanged: sync.Cond{ + L: &cl.mu, + }, } t.setChunkSize(defaultChunkSize) return diff --git a/torrent.go b/torrent.go index 0060cff1..78df5f2e 100644 --- a/torrent.go +++ b/torrent.go @@ -92,6 +92,7 @@ type Torrent struct { // Name used if the info name isn't available. Should be cleared when the // Info does become available. displayName string + // The bencoded bytes of the info dict. This is actively manipulated if // the info bytes aren't initially available, and we try to fetch them // from peers. @@ -99,6 +100,7 @@ type Torrent struct { // Each element corresponds to the 16KiB metadata pieces. If true, we have // received that piece. metadataCompletedChunks []bool + metadataChanged sync.Cond // Set when .Info is obtained. gotMetainfo missinggo.Event @@ -373,6 +375,7 @@ func (t *Torrent) setMetadataSize(bytes int64) (err error) { } t.metadataBytes = make([]byte, bytes) t.metadataCompletedChunks = make([]bool, (bytes+(1<<14)-1)/(1<<14)) + t.metadataChanged.Broadcast() for c := range t.conns { c.requestPendingMetadata() } diff --git a/torrent_test.go b/torrent_test.go index 4c5ac447..00f59498 100644 --- a/torrent_test.go +++ b/torrent_test.go @@ -1,6 +1,7 @@ package torrent import ( + "net" "os" "path/filepath" "testing" @@ -13,11 +14,11 @@ import ( "github.com/anacrolix/torrent/bencode" "github.com/anacrolix/torrent/internal/testutil" "github.com/anacrolix/torrent/metainfo" - "github.com/anacrolix/torrent/peer_protocol" + pp "github.com/anacrolix/torrent/peer_protocol" "github.com/anacrolix/torrent/storage" ) -func r(i, b, l peer_protocol.Integer) request { +func r(i, b, l pp.Integer) request { return request{i, chunkSpec{b, l}} } @@ -156,3 +157,60 @@ func TestPieceHashFailed(t *testing.T) { require.False(t, tt.pieceAllDirty(1)) tt.cl.mu.Unlock() } + +// Check the behaviour of Torrent.Metainfo when metadata is not completed. +func TestTorrentMetainfoIncompleteMetadata(t *testing.T) { + cfg := TestingConfig() + cfg.Debug = true + cl, err := NewClient(cfg) + require.NoError(t, err) + defer cl.Close() + + mi := testutil.GreetingMetaInfo() + ih := mi.HashInfoBytes() + + tt, _ := cl.AddTorrentInfoHash(ih) + assert.Nil(t, tt.Metainfo().InfoBytes) + assert.False(t, tt.haveAllMetadataPieces()) + + nc, err := net.Dial("tcp", cl.ListenAddr().String()) + require.NoError(t, err) + defer nc.Close() + + var pex peerExtensionBytes + pex.SetBit(ExtensionBitExtended) + hr, ok, err := handshake(nc, &ih, [20]byte{}, pex) + require.NoError(t, err) + assert.True(t, ok) + assert.True(t, hr.peerExtensionBytes.GetBit(ExtensionBitExtended)) + assert.EqualValues(t, cl.PeerID(), hr.peerID) + assert.Equal(t, ih, hr.Hash) + + assert.EqualValues(t, 0, tt.metadataSize()) + + func() { + cl.mu.Lock() + defer cl.mu.Unlock() + go func() { + _, err = nc.Write(pp.Message{ + Type: pp.Extended, + ExtendedID: pp.HandshakeExtendedID, + ExtendedPayload: func() []byte { + d := map[string]interface{}{ + "metadata_size": len(mi.InfoBytes), + } + b, err := bencode.Marshal(d) + if err != nil { + panic(err) + } + return b + }(), + }.MustMarshalBinary()) + require.NoError(t, err) + }() + tt.metadataChanged.Wait() + }() + assert.Equal(t, make([]byte, len(mi.InfoBytes)), tt.metadataBytes) + assert.False(t, tt.haveAllMetadataPieces()) + assert.Nil(t, tt.Metainfo().InfoBytes) +}