github.com/anacrolix/torrent@v1.61.0/fs/stream-sintel_test.go (about) 1 //go:build !windows 2 3 package torrentfs_test 4 5 import ( 6 "context" 7 "crypto/md5" 8 "encoding/hex" 9 "errors" 10 "fmt" 11 "io" 12 "io/fs" 13 "os" 14 "os/signal" 15 "path/filepath" 16 "testing" 17 "time" 18 19 "github.com/anacrolix/fuse" 20 fusefs "github.com/anacrolix/fuse/fs" 21 "github.com/anacrolix/missinggo/v2/panicif" 22 "github.com/go-quicktest/qt" 23 "golang.org/x/sync/errgroup" 24 25 "github.com/anacrolix/torrent" 26 torrentfs "github.com/anacrolix/torrent/fs" 27 "github.com/anacrolix/torrent/internal/testutil" 28 "github.com/anacrolix/torrent/metainfo" 29 ) 30 31 func copyFile(src, dst string) (err error) { 32 from, err := os.Open(src) 33 if err != nil { 34 return 35 } 36 defer from.Close() 37 to, err := os.Create(dst) 38 if err != nil { 39 return 40 } 41 defer to.Close() 42 _, err = io.Copy(to, from) 43 if err != nil { 44 return 45 } 46 return to.Close() 47 } 48 49 func TestStreamSintelMagnet(t *testing.T) { 50 t.Skip("flaky and fuck this shit") 51 ctx := t.Context() 52 ctx, cancel := signal.NotifyContext(ctx, os.Interrupt) 53 defer cancel() 54 fileHashes := map[string]string{ 55 "poster.jpg": "f9223791908131c505d7bdafa7a8aaf5", 56 "Sintel.mp4": "083e808d56aa7b146f513b3458658292", 57 } 58 targetFile := "Sintel.mp4" 59 if testing.Short() { 60 targetFile = "poster.jpg" 61 } 62 dir := t.TempDir() 63 t.Logf("temp dir: %v", dir) 64 metainfoDir := filepath.Join(dir, "torrents") 65 mountDir := filepath.Join(dir, "mnt") 66 sourceTorrentDir := `../testdata` 67 dummyTorrent := filepath.Join(sourceTorrentDir, `debian-10.8.0-amd64-netinst.iso.torrent`) 68 t.Log(os.Getwd()) 69 dummyTorrentDst := filepath.Join(metainfoDir, filepath.Base(dummyTorrent)) 70 err := os.MkdirAll(filepath.Dir(dummyTorrentDst), 0o700) 71 panicif.Err(err) 72 err = copyFile(dummyTorrent, dummyTorrentDst) 73 panicif.Err(err) 74 mi, err := metainfo.LoadFromFile(filepath.Join(sourceTorrentDir, `sintel.torrent`)) 75 panicif.Err(err) 76 m, err := mi.MagnetV2() 77 panicif.Err(err) 78 err = os.WriteFile(filepath.Join(metainfoDir, "sintel.magnet"), []byte(m.String()), 0600) 79 panicif.Err(err) 80 cfg := torrent.NewDefaultClientConfig() 81 //cfg.Debug = true 82 cfg.ListenPort = 0 83 cl, err := torrent.NewClient(cfg) 84 panicif.Err(err) 85 testutil.ExportStatusWriter(cl, "", t) 86 defer cl.Close() 87 88 err = os.Mkdir(mountDir, 0700) 89 panicif.Err(err) 90 conn, err := fuse.Mount(mountDir) 91 panicif.Err(err) 92 t.Cleanup(func() { fuse.Unmount(mountDir) }) 93 t.Cleanup(func() { conn.Close() }) 94 fs := torrentfs.New(cl) 95 var eg errgroup.Group 96 eg.Go(func() (err error) { 97 err = fusefs.Serve(conn, fs) 98 if err != nil { 99 err = fmt.Errorf("serving fuse: %w", err) 100 t.Log(err) 101 return 102 } 103 return 104 }) 105 <-conn.Ready 106 err = conn.MountError 107 if err != nil { 108 err = fmt.Errorf("conn mount error: %w", err) 109 } 110 111 go func() { 112 _, err := cl.AddTorrent(mi) 113 panicif.Err(err) 114 _, err = cl.AddMagnet(m.String()) 115 panicif.Err(err) 116 }() 117 118 f, err := openFileWhenExists(t, filepath.Join(mountDir, "Sintel", targetFile)) 119 panicif.Err(err) 120 t.Logf("opened %v", f.Name()) 121 t.Cleanup(func() { f.Close() }) 122 123 fi, err := f.Stat() 124 panicif.Err(err) 125 126 var written int64 127 w := writer{ 128 onWrite: func(p []byte) (n int, err error) { 129 written += int64(len(p)) 130 t.Logf("wrote %v bytes", len(p)) 131 t.Logf("progress %v", float64(written)/float64(fi.Size())) 132 return len(p), nil 133 }, 134 } 135 h := md5.New() 136 go func() { 137 <-ctx.Done() 138 f.Close() 139 }() 140 _, err = f.WriteTo(io.MultiWriter(h, &w)) 141 if ctx.Err() != nil { 142 t.Fatal(ctx.Err()) 143 } 144 panicif.Err(err) 145 err = f.Close() 146 panicif.Err(err) 147 148 qt.Assert(t, qt.Equals(hex.EncodeToString(h.Sum(nil)), fileHashes[targetFile])) 149 150 err = fuse.Unmount(mountDir) 151 panicif.Err(err) 152 err = eg.Wait() 153 panicif.Err(err) 154 } 155 156 func openFileWhenExists(t *testing.T, name string) (f *os.File, err error) { 157 ctx := t.Context() 158 for { 159 f, err = os.Open(name) 160 if err == nil { 161 return 162 } 163 if !errors.Is(err, fs.ErrNotExist) { 164 return 165 } 166 t.Logf("file does not yet exist: %v", name) 167 select { 168 case <-ctx.Done(): 169 err = context.Cause(ctx) 170 return 171 case <-time.After(1 * time.Second): 172 } 173 } 174 } 175 176 type writer struct { 177 onWrite func(b []byte) (n int, err error) 178 } 179 180 func (w writer) Write(p []byte) (n int, err error) { 181 return w.onWrite(p) 182 }