github.com/uber/kraken@v0.1.4/lib/torrent/storage/agentstorage/torrent_archive_test.go (about) 1 // Copyright (c) 2016-2019 Uber Technologies, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 package agentstorage 15 16 import ( 17 "os" 18 "sync" 19 "testing" 20 21 "github.com/uber/kraken/core" 22 "github.com/uber/kraken/lib/store" 23 "github.com/uber/kraken/lib/store/metadata" 24 "github.com/uber/kraken/lib/torrent/storage" 25 "github.com/uber/kraken/lib/torrent/storage/piecereader" 26 "github.com/uber/kraken/mocks/tracker/metainfoclient" 27 "github.com/uber/kraken/tracker/metainfoclient" 28 "github.com/uber/kraken/utils/bitsetutil" 29 "github.com/uber/kraken/utils/testutil" 30 31 "github.com/golang/mock/gomock" 32 "github.com/stretchr/testify/require" 33 "github.com/uber-go/tally" 34 ) 35 36 const pieceLength = 4 37 38 type archiveMocks struct { 39 cads *store.CADownloadStore 40 metaInfoClient *mockmetainfoclient.MockClient 41 } 42 43 func newArchiveMocks(t *testing.T) (*archiveMocks, func()) { 44 var cleanup testutil.Cleanup 45 46 ctrl := gomock.NewController(t) 47 cleanup.Add(ctrl.Finish) 48 49 cads, c := store.CADownloadStoreFixture() 50 cleanup.Add(c) 51 52 metaInfoClient := mockmetainfoclient.NewMockClient(ctrl) 53 54 return &archiveMocks{cads, metaInfoClient}, cleanup.Run 55 } 56 57 func (m *archiveMocks) new() *TorrentArchive { 58 return NewTorrentArchive(tally.NoopScope, m.cads, m.metaInfoClient) 59 } 60 61 func TestTorrentArchiveStatBitfield(t *testing.T) { 62 require := require.New(t) 63 64 mocks, cleanup := newArchiveMocks(t) 65 defer cleanup() 66 67 archive := mocks.new() 68 69 namespace := core.TagFixture() 70 blob := core.SizedBlobFixture(4, 1) 71 mi := blob.MetaInfo 72 73 mocks.metaInfoClient.EXPECT().Download(namespace, mi.Digest()).Return(mi, nil).Times(1) 74 75 tor, err := archive.CreateTorrent(namespace, mi.Digest()) 76 require.NoError(err) 77 78 require.NoError(tor.WritePiece(piecereader.NewBuffer(blob.Content[2:3]), 2)) 79 80 info, err := archive.Stat(namespace, mi.Digest()) 81 require.NoError(err) 82 require.Equal(bitsetutil.FromBools(false, false, true, false), info.Bitfield()) 83 require.Equal(int64(1), info.MaxPieceLength()) 84 } 85 86 func TestTorrentArchiveStatNotExist(t *testing.T) { 87 require := require.New(t) 88 89 mocks, cleanup := newArchiveMocks(t) 90 defer cleanup() 91 92 archive := mocks.new() 93 94 namespace := core.TagFixture() 95 d := core.DigestFixture() 96 97 _, err := archive.Stat(namespace, d) 98 require.True(os.IsNotExist(err)) 99 } 100 101 func TestTorrentArchiveCreateTorrent(t *testing.T) { 102 require := require.New(t) 103 104 mocks, cleanup := newArchiveMocks(t) 105 defer cleanup() 106 107 archive := mocks.new() 108 109 mi := core.MetaInfoFixture() 110 namespace := core.TagFixture() 111 112 mocks.metaInfoClient.EXPECT().Download(namespace, mi.Digest()).Return(mi, nil) 113 114 tor, err := archive.CreateTorrent(namespace, mi.Digest()) 115 require.NoError(err) 116 require.NotNil(tor) 117 118 // Check metainfo. 119 var tm metadata.TorrentMeta 120 require.NoError(mocks.cads.Any().GetMetadata(mi.Digest().Hex(), &tm)) 121 require.Equal(mi, tm.MetaInfo) 122 123 // Create again reads from disk. 124 tor, err = archive.CreateTorrent(namespace, mi.Digest()) 125 require.NoError(err) 126 require.NotNil(tor) 127 } 128 129 func TestTorrentArchiveCreateTorrentNotFound(t *testing.T) { 130 require := require.New(t) 131 132 mocks, cleanup := newArchiveMocks(t) 133 defer cleanup() 134 135 archive := mocks.new() 136 137 mi := core.MetaInfoFixture() 138 namespace := core.TagFixture() 139 140 mocks.metaInfoClient.EXPECT().Download(namespace, mi.Digest()).Return(nil, metainfoclient.ErrNotFound) 141 142 _, err := archive.CreateTorrent(namespace, mi.Digest()) 143 require.Equal(storage.ErrNotFound, err) 144 } 145 146 func TestTorrentArchiveDeleteTorrent(t *testing.T) { 147 require := require.New(t) 148 149 mocks, cleanup := newArchiveMocks(t) 150 defer cleanup() 151 152 archive := mocks.new() 153 154 mi := core.MetaInfoFixture() 155 namespace := core.TagFixture() 156 157 mocks.metaInfoClient.EXPECT().Download(namespace, mi.Digest()).Return(mi, nil) 158 159 tor, err := archive.CreateTorrent(namespace, mi.Digest()) 160 require.NoError(err) 161 require.NotNil(tor) 162 163 require.NoError(archive.DeleteTorrent(mi.Digest())) 164 165 _, err = archive.Stat(namespace, mi.Digest()) 166 require.True(os.IsNotExist(err)) 167 } 168 169 func TestTorrentArchiveConcurrentGet(t *testing.T) { 170 require := require.New(t) 171 172 mocks, cleanup := newArchiveMocks(t) 173 defer cleanup() 174 175 archive := mocks.new() 176 177 mi := core.MetaInfoFixture() 178 namespace := core.TagFixture() 179 180 // Allow any times for concurrency below. 181 mocks.metaInfoClient.EXPECT().Download(namespace, mi.Digest()).Return(mi, nil).AnyTimes() 182 183 var wg sync.WaitGroup 184 for i := 0; i < 50; i++ { 185 wg.Add(1) 186 go func() { 187 defer wg.Done() 188 tor, err := archive.CreateTorrent(namespace, mi.Digest()) 189 require.NoError(err) 190 require.NotNil(tor) 191 }() 192 } 193 wg.Wait() 194 } 195 196 func TestTorrentArchiveGetTorrent(t *testing.T) { 197 require := require.New(t) 198 199 mocks, cleanup := newArchiveMocks(t) 200 defer cleanup() 201 202 archive := mocks.new() 203 204 mi := core.MetaInfoFixture() 205 namespace := core.TagFixture() 206 207 // Since metainfo is not yet on disk, get should fail. 208 _, err := archive.GetTorrent(namespace, mi.Digest()) 209 require.Error(err) 210 211 mocks.metaInfoClient.EXPECT().Download(namespace, mi.Digest()).Return(mi, nil) 212 213 _, err = archive.CreateTorrent(namespace, mi.Digest()) 214 require.NoError(err) 215 216 // After creating the torrent, get should succeed. 217 tor, err := archive.GetTorrent(namespace, mi.Digest()) 218 require.NoError(err) 219 require.NotNil(tor) 220 }