})
}
-// Return a Torrent ready for insertion into a Client.
+// Return a Torrent ready for insertion into a Client. This is also the method to call to create
+// Torrents for testing.
func (cl *Client) newTorrentOpt(opts AddTorrentOpts) (t *Torrent) {
var v1InfoHash g.Option[infohash.T]
if !opts.InfoHash.IsZero() {
webSeeds: make(map[string]*Peer),
gotMetainfoC: make(chan struct{}),
}
+ t.closedCtx, t.closedCtxCancel = context.WithCancel(context.Background())
var salt [8]byte
rand.Read(salt[:])
t.smartBanCache.Hash = func(b []byte) uint64 {
}
func GreetingMetaInfo() *metainfo.MetaInfo {
- return Greeting.Metainfo(5)
+ mi, _ := Greeting.Generate(5)
+ return &mi
}
// Gives a temporary directory containing the completed "greeting" torrent,
Data string
}
+// High-level description of a torrent for testing purposes.
type Torrent struct {
Files []File
Name string
return info
}
-func (t *Torrent) Metainfo(pieceLength int64) *metainfo.MetaInfo {
- mi := metainfo.MetaInfo{}
+// Create an info and metainfo with bytes set for the torrent with the provided piece length.
+func (t *Torrent) Generate(pieceLength int64) (mi metainfo.MetaInfo, info metainfo.Info) {
var err error
- mi.InfoBytes, err = bencode.Marshal(t.Info(pieceLength))
+ info = t.Info(pieceLength)
+ mi.InfoBytes, err = bencode.Marshal(info)
expect.Nil(err)
- return &mi
+ return
}
dataUploadDisallowed bool
userOnWriteChunkErr func(error)
- closed chansync.SetOnce
- onClose []func()
+ closed chansync.SetOnce
+ // A background Context cancelled when the Torrent is closed. Added to minimize extra goroutines
+ // in tracker handlers.
+ closedCtx context.Context
+ closedCtxCancel func()
+ onClose []func()
infoHash g.Option[metainfo.Hash]
infoHashV2 g.Option[infohash_v2.T]
err = errors.New("already closed")
return
}
+ t.closedCtxCancel()
for _, f := range t.onClose {
f()
}
"testing"
g "github.com/anacrolix/generics"
- "github.com/anacrolix/log"
"github.com/anacrolix/missinggo/v2"
"github.com/anacrolix/missinggo/v2/bitmap"
qt "github.com/frankban/quicktest"
func TestRelativeAvailabilityHaveNone(t *testing.T) {
c := qt.New(t)
var err error
- cl := Client{
- config: TestingConfig(t),
- }
- tt := Torrent{
- cl: &cl,
- logger: log.Default,
- gotMetainfoC: make(chan struct{}),
- }
+ cl := newTestingClient(t)
+ mi, info := testutil.Greeting.Generate(5)
+ tt := cl.newTorrentOpt(AddTorrentOpts{InfoHash: mi.HashInfoBytes()})
tt.setChunkSize(2)
g.MakeMapIfNil(&tt.conns)
pc := PeerConn{}
- pc.t = &tt
+ pc.t = tt
pc.legacyPeerImpl = &pc
pc.initRequestState()
g.InitNew(&pc.callbacks)
tt.conns[&pc] = struct{}{}
err = pc.peerSentHave(0)
c.Assert(err, qt.IsNil)
- info := testutil.Greeting.Info(5)
err = tt.setInfo(&info)
c.Assert(err, qt.IsNil)
tt.onSetInfo()
func (me *trackerScraper) Run() {
defer me.announceStopped()
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
- // TODO: Get rid of the need for this.
- go func() {
- defer cancel()
- select {
- case <-ctx.Done():
- case <-me.t.Closed():
- }
- }()
-
// make sure first announce is a "started"
e := tracker.Started
for {
- ar := me.announce(ctx, e)
+ ar := me.announce(me.t.closedCtx, e)
// after first announce, get back to regular "none"
e = tracker.None
me.t.cl.lock()