9 "github.com/anacrolix/log"
10 pp "github.com/anacrolix/torrent/peer_protocol"
12 "github.com/stretchr/testify/assert"
13 "github.com/stretchr/testify/require"
15 "github.com/anacrolix/torrent"
16 "github.com/anacrolix/torrent/internal/testutil"
17 "github.com/anacrolix/torrent/metainfo"
18 "github.com/anacrolix/torrent/storage"
21 func justOneNetwork(cc *torrent.ClientConfig) {
26 func TestReceiveChunkStorageFailureSeederFastExtensionDisabled(t *testing.T) {
27 testReceiveChunkStorageFailure(t, false)
30 func TestReceiveChunkStorageFailure(t *testing.T) {
31 testReceiveChunkStorageFailure(t, true)
34 func testReceiveChunkStorageFailure(t *testing.T, seederFast bool) {
35 seederDataDir, metainfo := testutil.GreetingTestTorrent()
36 defer os.RemoveAll(seederDataDir)
37 seederClientConfig := torrent.TestingConfig()
38 seederClientConfig.Debug = true
39 justOneNetwork(seederClientConfig)
40 seederClientStorage := storage.NewMMap(seederDataDir)
41 defer seederClientStorage.Close()
42 seederClientConfig.DefaultStorage = seederClientStorage
43 seederClientConfig.Seed = true
44 seederClientConfig.Debug = true
45 seederClientConfig.Extensions.SetBit(pp.ExtensionBitFast, seederFast)
46 seederClient, err := torrent.NewClient(seederClientConfig)
47 require.NoError(t, err)
48 defer seederClient.Close()
49 defer testutil.ExportStatusWriter(seederClient, "s")()
50 leecherClientConfig := torrent.TestingConfig()
51 leecherClientConfig.Debug = true
52 justOneNetwork(leecherClientConfig)
53 leecherClient, err := torrent.NewClient(leecherClientConfig)
54 require.NoError(t, err)
55 defer leecherClient.Close()
56 defer testutil.ExportStatusWriter(leecherClient, "l")()
57 info, err := metainfo.UnmarshalInfo()
58 require.NoError(t, err)
59 leecherStorage := diskFullStorage{
60 pieces: make([]pieceState, info.NumPieces()),
61 data: make([]byte, info.TotalLength()),
63 defer leecherStorage.Close()
64 leecherTorrent, new, err := leecherClient.AddTorrentSpec(&torrent.TorrentSpec{
65 InfoHash: metainfo.HashInfoBytes(),
66 Storage: &leecherStorage,
68 leecherStorage.t = leecherTorrent
69 require.NoError(t, err)
71 seederTorrent, err := seederClient.AddTorrent(metainfo)
72 require.NoError(t, err)
73 // Tell the seeder to find the leecher. Is it guaranteed seeders will always try to do this?
74 seederTorrent.AddClientPeer(leecherClient)
75 <-leecherTorrent.GotInfo()
76 assertReadAllGreeting(t, leecherTorrent.NewReader())
77 // TODO: Check that PeerConns fastEnabled matches seederFast?
81 type pieceState struct {
85 type diskFullStorage struct {
88 defaultHandledWriteChunkError bool
95 func (me *diskFullStorage) Piece(p metainfo.Piece) storage.PieceImpl {
102 func (me diskFullStorage) Close() error {
106 func (d diskFullStorage) OpenTorrent(info *metainfo.Info, infoHash metainfo.Hash) (storage.TorrentImpl, error) {
110 type pieceImpl struct {
115 func (me pieceImpl) state() *pieceState {
116 return &me.diskFullStorage.pieces[me.mip.Index()]
119 func (me pieceImpl) ReadAt(p []byte, off int64) (n int, err error) {
120 off += me.mip.Offset()
121 return copy(p, me.data[off:]), nil
124 func (me pieceImpl) WriteAt(p []byte, off int64) (int, error) {
125 off += me.mip.Offset()
126 if !me.defaultHandledWriteChunkError {
128 me.t.SetOnWriteChunkError(func(err error) {
129 log.Printf("got write chunk error to custom handler: %v", err)
131 me.diskNotFull = true
133 me.t.AllowDataDownload()
135 me.t.AllowDataDownload()
137 me.defaultHandledWriteChunkError = true
142 return copy(me.data[off:], p), nil
144 return copy(me.data[off:], p[:1]), errors.New("disk full")
147 func (me pieceImpl) MarkComplete() error {
148 me.state().complete = true
152 func (me pieceImpl) MarkNotComplete() error {
153 panic("implement me")
156 func (me pieceImpl) Completion() storage.Completion {
157 return storage.Completion{
158 Complete: me.state().complete,