github.com/susy-go/susy-graviton@v0.0.0-20190614130430-36cddae42305/swarm/storage/localstore/index_test.go (about) 1 // Copyleft 2018 The susy-graviton Authors 2 // This file is part of the susy-graviton library. 3 // 4 // The susy-graviton library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The susy-graviton library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MSRCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the susy-graviton library. If not, see <http://www.gnu.org/licenses/>. 16 17 package localstore 18 19 import ( 20 "bytes" 21 "math/rand" 22 "testing" 23 24 "github.com/susy-go/susy-graviton/swarm/storage" 25 ) 26 27 // TestDB_pullIndex validates the ordering of keys in pull index. 28 // Pull index key contains PO prefix which is calculated from 29 // DB base key and chunk address. This is not an Item field 30 // which are checked in Mode tests. 31 // This test uploads chunks, sorts them in expected order and 32 // validates that pull index iterator will iterate it the same 33 // order. 34 func TestDB_pullIndex(t *testing.T) { 35 db, cleanupFunc := newTestDB(t, nil) 36 defer cleanupFunc() 37 38 uploader := db.NewPutter(ModePutUpload) 39 40 chunkCount := 50 41 42 chunks := make([]testIndexChunk, chunkCount) 43 44 // upload random chunks 45 for i := 0; i < chunkCount; i++ { 46 chunk := generateRandomChunk() 47 48 err := uploader.Put(chunk) 49 if err != nil { 50 t.Fatal(err) 51 } 52 53 chunks[i] = testIndexChunk{ 54 Chunk: chunk, 55 // this timestamp is not the same as in 56 // the index, but given that uploads 57 // are sequential and that only ordering 58 // of events matter, this information is 59 // sufficient 60 storeTimestamp: now(), 61 } 62 } 63 64 testItemsOrder(t, db.pullIndex, chunks, func(i, j int) (less bool) { 65 poi := storage.Proximity(db.baseKey, chunks[i].Address()) 66 poj := storage.Proximity(db.baseKey, chunks[j].Address()) 67 if poi < poj { 68 return true 69 } 70 if poi > poj { 71 return false 72 } 73 if chunks[i].storeTimestamp < chunks[j].storeTimestamp { 74 return true 75 } 76 if chunks[i].storeTimestamp > chunks[j].storeTimestamp { 77 return false 78 } 79 return bytes.Compare(chunks[i].Address(), chunks[j].Address()) == -1 80 }) 81 } 82 83 // TestDB_gcIndex validates garbage collection index by uploading 84 // a chunk with and performing operations using synced, access and 85 // request modes. 86 func TestDB_gcIndex(t *testing.T) { 87 db, cleanupFunc := newTestDB(t, nil) 88 defer cleanupFunc() 89 90 uploader := db.NewPutter(ModePutUpload) 91 92 chunkCount := 50 93 94 chunks := make([]testIndexChunk, chunkCount) 95 96 // upload random chunks 97 for i := 0; i < chunkCount; i++ { 98 chunk := generateRandomChunk() 99 100 err := uploader.Put(chunk) 101 if err != nil { 102 t.Fatal(err) 103 } 104 105 chunks[i] = testIndexChunk{ 106 Chunk: chunk, 107 } 108 } 109 110 // check if all chunks are stored 111 newItemsCountTest(db.pullIndex, chunkCount)(t) 112 113 // check that chunks are not collectable for garbage 114 newItemsCountTest(db.gcIndex, 0)(t) 115 116 // set update gc test hook to signal when 117 // update gc goroutine is done by sending to 118 // testHookUpdateGCChan channel, which is 119 // used to wait for indexes change verifications 120 testHookUpdateGCChan := make(chan struct{}) 121 defer setTestHookUpdateGC(func() { 122 testHookUpdateGCChan <- struct{}{} 123 })() 124 125 t.Run("request unsynced", func(t *testing.T) { 126 chunk := chunks[1] 127 128 _, err := db.NewGetter(ModeGetRequest).Get(chunk.Address()) 129 if err != nil { 130 t.Fatal(err) 131 } 132 // wait for update gc goroutine to be done 133 <-testHookUpdateGCChan 134 135 // the chunk is not synced 136 // should not be in the garbace collection index 137 newItemsCountTest(db.gcIndex, 0)(t) 138 139 newIndexGCSizeTest(db)(t) 140 }) 141 142 t.Run("sync one chunk", func(t *testing.T) { 143 chunk := chunks[0] 144 145 err := db.NewSetter(ModeSetSync).Set(chunk.Address()) 146 if err != nil { 147 t.Fatal(err) 148 } 149 150 // the chunk is synced and should be in gc index 151 newItemsCountTest(db.gcIndex, 1)(t) 152 153 newIndexGCSizeTest(db)(t) 154 }) 155 156 t.Run("sync all chunks", func(t *testing.T) { 157 setter := db.NewSetter(ModeSetSync) 158 159 for i := range chunks { 160 err := setter.Set(chunks[i].Address()) 161 if err != nil { 162 t.Fatal(err) 163 } 164 } 165 166 testItemsOrder(t, db.gcIndex, chunks, nil) 167 168 newIndexGCSizeTest(db)(t) 169 }) 170 171 t.Run("request one chunk", func(t *testing.T) { 172 i := 6 173 174 _, err := db.NewGetter(ModeGetRequest).Get(chunks[i].Address()) 175 if err != nil { 176 t.Fatal(err) 177 } 178 // wait for update gc goroutine to be done 179 <-testHookUpdateGCChan 180 181 // move the chunk to the end of the expected gc 182 c := chunks[i] 183 chunks = append(chunks[:i], chunks[i+1:]...) 184 chunks = append(chunks, c) 185 186 testItemsOrder(t, db.gcIndex, chunks, nil) 187 188 newIndexGCSizeTest(db)(t) 189 }) 190 191 t.Run("random chunk request", func(t *testing.T) { 192 requester := db.NewGetter(ModeGetRequest) 193 194 rand.Shuffle(len(chunks), func(i, j int) { 195 chunks[i], chunks[j] = chunks[j], chunks[i] 196 }) 197 198 for _, chunk := range chunks { 199 _, err := requester.Get(chunk.Address()) 200 if err != nil { 201 t.Fatal(err) 202 } 203 // wait for update gc goroutine to be done 204 <-testHookUpdateGCChan 205 } 206 207 testItemsOrder(t, db.gcIndex, chunks, nil) 208 209 newIndexGCSizeTest(db)(t) 210 }) 211 212 t.Run("remove one chunk", func(t *testing.T) { 213 i := 3 214 215 err := db.NewSetter(modeSetRemove).Set(chunks[i].Address()) 216 if err != nil { 217 t.Fatal(err) 218 } 219 220 // remove the chunk from the expected chunks in gc index 221 chunks = append(chunks[:i], chunks[i+1:]...) 222 223 testItemsOrder(t, db.gcIndex, chunks, nil) 224 225 newIndexGCSizeTest(db)(t) 226 }) 227 }