10 "github.com/stretchr/testify/assert"
11 "github.com/stretchr/testify/require"
13 "github.com/anacrolix/torrent"
14 "github.com/anacrolix/torrent/internal/testutil"
15 "github.com/anacrolix/torrent/metainfo"
16 "github.com/anacrolix/torrent/storage"
19 func justOneNetwork(cc *torrent.ClientConfig) {
24 func TestReceiveChunkStorageFailure(t *testing.T) {
25 seederDataDir, metainfo := testutil.GreetingTestTorrent()
26 defer os.RemoveAll(seederDataDir)
27 seederClientConfig := torrent.TestingConfig()
28 seederClientConfig.Debug = true
29 justOneNetwork(seederClientConfig)
30 seederClientStorage := storage.NewMMap(seederDataDir)
31 defer seederClientStorage.Close()
32 seederClientConfig.DefaultStorage = seederClientStorage
33 seederClientConfig.Seed = true
34 seederClientConfig.Debug = true
35 seederClient, err := torrent.NewClient(seederClientConfig)
36 require.NoError(t, err)
37 defer testutil.ExportStatusWriter(seederClient, "s")()
38 leecherClientConfig := torrent.TestingConfig()
39 leecherClientConfig.Debug = true
40 justOneNetwork(leecherClientConfig)
41 leecherClient, err := torrent.NewClient(leecherClientConfig)
42 require.NoError(t, err)
43 defer testutil.ExportStatusWriter(leecherClient, "l")()
44 info, err := metainfo.UnmarshalInfo()
45 require.NoError(t, err)
46 leecherStorage := diskFullStorage{
47 pieces: make([]pieceState, info.NumPieces()),
48 data: make([]byte, info.TotalLength()),
50 defer leecherStorage.Close()
51 leecherTorrent, new, err := leecherClient.AddTorrentSpec(&torrent.TorrentSpec{
52 InfoHash: metainfo.HashInfoBytes(),
53 Storage: &leecherStorage,
55 leecherStorage.t = leecherTorrent
56 require.NoError(t, err)
58 seederTorrent, err := seederClient.AddTorrent(metainfo)
59 require.NoError(t, err)
60 // Tell the seeder to find the leecher. Is it guaranteed seeders will always try to do this?
61 seederTorrent.AddClientPeer(leecherClient)
62 <-leecherTorrent.GotInfo()
63 assertReadAllGreeting(t, leecherTorrent.NewReader())
66 type pieceState struct {
70 type diskFullStorage struct {
73 defaultHandledWriteChunkError bool
80 func (me *diskFullStorage) Piece(p metainfo.Piece) storage.PieceImpl {
87 func (me diskFullStorage) Close() error {
91 func (d diskFullStorage) OpenTorrent(info *metainfo.Info, infoHash metainfo.Hash) (storage.TorrentImpl, error) {
95 type pieceImpl struct {
100 func (me pieceImpl) state() *pieceState {
101 return &me.diskFullStorage.pieces[me.mip.Index()]
104 func (me pieceImpl) ReadAt(p []byte, off int64) (n int, err error) {
105 off += me.mip.Offset()
106 return copy(p, me.data[off:]), nil
109 func (me pieceImpl) WriteAt(p []byte, off int64) (int, error) {
110 off += me.mip.Offset()
111 if !me.defaultHandledWriteChunkError {
113 me.t.SetOnWriteChunkError(func(err error) {
114 log.Printf("got write chunk error to custom handler: %v", err)
116 me.diskNotFull = true
118 me.t.AllowDataDownload()
120 me.t.AllowDataDownload()
122 me.defaultHandledWriteChunkError = true
127 return copy(me.data[off:], p), nil
129 return copy(me.data[off:], p[:1]), errors.New("disk full")
132 func (me pieceImpl) MarkComplete() error {
133 me.state().complete = true
137 func (me pieceImpl) MarkNotComplete() error {
138 panic("implement me")
141 func (me pieceImpl) Completion() storage.Completion {
142 return storage.Completion{
143 Complete: me.state().complete,