9 "github.com/anacrolix/log"
11 "github.com/stretchr/testify/assert"
12 "github.com/stretchr/testify/require"
14 "github.com/anacrolix/torrent"
15 "github.com/anacrolix/torrent/internal/testutil"
16 "github.com/anacrolix/torrent/metainfo"
17 "github.com/anacrolix/torrent/storage"
20 func justOneNetwork(cc *torrent.ClientConfig) {
25 func TestReceiveChunkStorageFailure(t *testing.T) {
26 seederDataDir, metainfo := testutil.GreetingTestTorrent()
27 defer os.RemoveAll(seederDataDir)
28 seederClientConfig := torrent.TestingConfig()
29 seederClientConfig.Debug = true
30 justOneNetwork(seederClientConfig)
31 seederClientStorage := storage.NewMMap(seederDataDir)
32 defer seederClientStorage.Close()
33 seederClientConfig.DefaultStorage = seederClientStorage
34 seederClientConfig.Seed = true
35 seederClientConfig.Debug = true
36 seederClient, err := torrent.NewClient(seederClientConfig)
37 require.NoError(t, err)
38 defer testutil.ExportStatusWriter(seederClient, "s")()
39 leecherClientConfig := torrent.TestingConfig()
40 leecherClientConfig.Debug = true
41 justOneNetwork(leecherClientConfig)
42 leecherClient, err := torrent.NewClient(leecherClientConfig)
43 require.NoError(t, err)
44 defer testutil.ExportStatusWriter(leecherClient, "l")()
45 info, err := metainfo.UnmarshalInfo()
46 require.NoError(t, err)
47 leecherStorage := diskFullStorage{
48 pieces: make([]pieceState, info.NumPieces()),
49 data: make([]byte, info.TotalLength()),
51 defer leecherStorage.Close()
52 leecherTorrent, new, err := leecherClient.AddTorrentSpec(&torrent.TorrentSpec{
53 InfoHash: metainfo.HashInfoBytes(),
54 Storage: &leecherStorage,
56 leecherStorage.t = leecherTorrent
57 require.NoError(t, err)
59 seederTorrent, err := seederClient.AddTorrent(metainfo)
60 require.NoError(t, err)
61 // Tell the seeder to find the leecher. Is it guaranteed seeders will always try to do this?
62 seederTorrent.AddClientPeer(leecherClient)
63 <-leecherTorrent.GotInfo()
64 assertReadAllGreeting(t, leecherTorrent.NewReader())
67 type pieceState struct {
71 type diskFullStorage struct {
74 defaultHandledWriteChunkError bool
81 func (me *diskFullStorage) Piece(p metainfo.Piece) storage.PieceImpl {
88 func (me diskFullStorage) Close() error {
92 func (d diskFullStorage) OpenTorrent(info *metainfo.Info, infoHash metainfo.Hash) (storage.TorrentImpl, error) {
96 type pieceImpl struct {
101 func (me pieceImpl) state() *pieceState {
102 return &me.diskFullStorage.pieces[me.mip.Index()]
105 func (me pieceImpl) ReadAt(p []byte, off int64) (n int, err error) {
106 off += me.mip.Offset()
107 return copy(p, me.data[off:]), nil
110 func (me pieceImpl) WriteAt(p []byte, off int64) (int, error) {
111 off += me.mip.Offset()
112 if !me.defaultHandledWriteChunkError {
114 me.t.SetOnWriteChunkError(func(err error) {
115 log.Printf("got write chunk error to custom handler: %v", err)
117 me.diskNotFull = true
119 me.t.AllowDataDownload()
121 me.t.AllowDataDownload()
123 me.defaultHandledWriteChunkError = true
128 return copy(me.data[off:], p), nil
130 return copy(me.data[off:], p[:1]), errors.New("disk full")
133 func (me pieceImpl) MarkComplete() error {
134 me.state().complete = true
138 func (me pieceImpl) MarkNotComplete() error {
139 panic("implement me")
142 func (me pieceImpl) Completion() storage.Completion {
143 return storage.Completion{
144 Complete: me.state().complete,