github.com/braveheart12/just@v0.8.7/ledger/storage/cleaner_test.go (about) 1 /* 2 * Copyright 2019 Insolar Technologies 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package storage_test 18 19 import ( 20 "context" 21 "fmt" 22 "testing" 23 24 "github.com/insolar/insolar/component" 25 "github.com/insolar/insolar/core" 26 "github.com/insolar/insolar/instrumentation/inslogger" 27 "github.com/insolar/insolar/ledger/recentstorage" 28 "github.com/insolar/insolar/ledger/storage" 29 "github.com/insolar/insolar/ledger/storage/storagetest" 30 "github.com/insolar/insolar/platformpolicy" 31 "github.com/insolar/insolar/testutils" 32 "github.com/stretchr/testify/assert" 33 "github.com/stretchr/testify/require" 34 "github.com/stretchr/testify/suite" 35 ) 36 37 type cleanerSuite struct { 38 suite.Suite 39 40 cm *component.Manager 41 ctx context.Context 42 cleaner func() 43 44 objectStorage storage.ObjectStorage 45 dropStorage storage.DropStorage 46 storageCleaner storage.Cleaner 47 } 48 49 func NewCleanerSuite() *cleanerSuite { 50 return &cleanerSuite{ 51 Suite: suite.Suite{}, 52 } 53 } 54 55 // Init and run suite 56 func TestCleaner(t *testing.T) { 57 suite.Run(t, NewCleanerSuite()) 58 } 59 60 func (s *cleanerSuite) BeforeTest(suiteName, testName string) { 61 s.cm = &component.Manager{} 62 s.ctx = inslogger.TestContext(s.T()) 63 64 db, cleaner := storagetest.TmpDB(s.ctx, s.T()) 65 s.cleaner = cleaner 66 67 s.objectStorage = storage.NewObjectStorage() 68 s.dropStorage = storage.NewDropStorage(0) 69 s.storageCleaner = storage.NewCleaner() 70 71 s.cm.Inject( 72 platformpolicy.NewPlatformCryptographyScheme(), 73 db, 74 s.objectStorage, 75 s.storageCleaner, 76 s.dropStorage, 77 ) 78 79 err := s.cm.Init(s.ctx) 80 if err != nil { 81 s.T().Error("ComponentManager init failed", err) 82 } 83 err = s.cm.Start(s.ctx) 84 if err != nil { 85 s.T().Error("ComponentManager start failed", err) 86 } 87 } 88 89 func (s *cleanerSuite) AfterTest(suiteName, testName string) { 90 err := s.cm.Stop(s.ctx) 91 if err != nil { 92 s.T().Error("ComponentManager stop failed", err) 93 } 94 s.cleaner() 95 } 96 97 func (s *cleanerSuite) Test_RemoveRecords() { 98 t := s.T() 99 ctx := inslogger.TestContext(t) 100 101 jetID00 := testutils.JetFromString("00") 102 jetID01 := testutils.JetFromString("01") 103 jetID11 := testutils.JetFromString("11") 104 jets := []core.RecordID{jetID00, jetID01, jetID11} 105 106 // should remove all records in rmJetID on pulses 1, 2, but all in pulse 3 for rmJetID should left 107 // and other jets records should not be removed too 108 var checks []cleanChecker 109 until := 2 110 rmUntilPN := core.PulseNumber(core.FirstPulseNumber + until + 1) 111 rmJetID := jetID01 112 113 for _, jetID := range jets { 114 for i := 1; i <= 3; i++ { 115 pn := core.PulseNumber(core.FirstPulseNumber + i) 116 117 shouldLeft := true 118 if jetID == rmJetID { 119 shouldLeft = i > until 120 } 121 122 blobID, err := storagetest.AddRandBlob(ctx, s.objectStorage, jetID, pn) 123 require.NoError(t, err) 124 blobCC := cleanCase{ 125 rectype: "blob", 126 id: blobID, 127 jetID: jetID, 128 pulseNum: pn, 129 shouldLeft: shouldLeft, 130 } 131 checks = append(checks, blobCase{ 132 cleanCase: blobCC, 133 objectStorage: s.objectStorage, 134 }) 135 136 recID, err := storagetest.AddRandRecord(ctx, s.objectStorage, jetID, pn) 137 require.NoError(t, err) 138 recCC := cleanCase{ 139 rectype: "record", 140 id: recID, 141 jetID: jetID, 142 pulseNum: pn, 143 shouldLeft: shouldLeft, 144 } 145 checks = append(checks, recordCase{ 146 cleanCase: recCC, 147 objectStorage: s.objectStorage, 148 }) 149 150 _, err = storagetest.AddRandDrop(ctx, s.dropStorage, jetID, pn) 151 require.NoError(t, err) 152 dropCC := cleanCase{ 153 rectype: "drop", 154 id: recID, 155 jetID: jetID, 156 pulseNum: pn, 157 shouldLeft: shouldLeft, 158 } 159 checks = append(checks, dropCase{ 160 cleanCase: dropCC, 161 dropStorage: s.dropStorage, 162 }) 163 } 164 } 165 166 s.storageCleaner.CleanJetRecordsUntilPulse(ctx, rmJetID, rmUntilPN) 167 168 for _, check := range checks { 169 check.Check(ctx, t) 170 } 171 } 172 173 func (s *cleanerSuite) Test_RemoveJetIndexes() { 174 t := s.T() 175 ctx := inslogger.TestContext(t) 176 177 jetID00 := testutils.JetFromString("00") 178 jetID01 := testutils.JetFromString("01") 179 jetID11 := testutils.JetFromString("11") 180 jets := []core.RecordID{jetID00, jetID01, jetID11} 181 182 // should remove records in Pulse 1, 2, but left 3 183 var checks []cleanChecker 184 until := 2 185 rmJetID := jetID01 186 var removeIndexes []core.RecordID 187 188 for _, jetID := range jets { 189 for i := 1; i <= 3; i++ { 190 pn := core.PulseNumber(core.FirstPulseNumber + i) 191 idxID, err := storagetest.AddRandIndex(ctx, s.objectStorage, jetID, pn) 192 require.NoError(t, err) 193 194 shouldLeft := true 195 if jetID == rmJetID { 196 shouldLeft = i > until 197 if !shouldLeft { 198 removeIndexes = append(removeIndexes, *idxID) 199 } 200 } 201 202 cc := cleanCase{ 203 id: idxID, 204 jetID: jetID, 205 pulseNum: pn, 206 shouldLeft: shouldLeft, 207 } 208 checks = append(checks, indexCase{ 209 cleanCase: cc, 210 objectStorage: s.objectStorage, 211 }) 212 } 213 } 214 215 recent := recentstorage.NewRecentIndexStorageMock(s.T()) 216 recent.FilterNotExistWithLockFunc = func(ctx context.Context, candidates []core.RecordID, fn func(fordelete []core.RecordID)) { 217 fn(candidates) 218 } 219 220 s.storageCleaner.CleanJetIndexes(ctx, rmJetID, recent, removeIndexes) 221 222 for _, check := range checks { 223 check.Check(ctx, t) 224 } 225 } 226 227 // check helpers 228 229 type cleanChecker interface { 230 Check(ctx context.Context, t *testing.T) 231 String() string 232 } 233 234 type cleanCase struct { 235 rectype string 236 id *core.RecordID 237 jetID core.RecordID 238 pulseNum core.PulseNumber 239 shouldLeft bool 240 } 241 242 func (cc cleanCase) String() string { 243 return fmt.Sprintf("%v jetID=%v, pulseNum=%v, shouldLeft=%v", 244 cc.rectype, cc.jetID.DebugString(), cc.pulseNum, cc.shouldLeft) 245 } 246 247 func (cc cleanCase) check(t *testing.T, err error) { 248 if cc.shouldLeft { 249 if !assert.NoError(t, err) { 250 fmt.Printf("%v => err: %T\n", cc, err) 251 } 252 return 253 } 254 if !assert.Exactly(t, err, core.ErrNotFound) { 255 fmt.Printf("%v => err: %T\n", cc, err) 256 } 257 } 258 259 type indexCase struct { 260 cleanCase 261 objectStorage storage.ObjectStorage 262 } 263 264 func (c indexCase) Check(ctx context.Context, t *testing.T) { 265 _, err := c.objectStorage.GetObjectIndex(ctx, c.jetID, c.id, false) 266 c.check(t, err) 267 } 268 269 type blobCase struct { 270 cleanCase 271 objectStorage storage.ObjectStorage 272 } 273 274 func (c blobCase) Check(ctx context.Context, t *testing.T) { 275 _, err := c.objectStorage.GetBlob(ctx, c.jetID, c.id) 276 c.check(t, err) 277 } 278 279 type recordCase struct { 280 cleanCase 281 objectStorage storage.ObjectStorage 282 } 283 284 func (c recordCase) Check(ctx context.Context, t *testing.T) { 285 _, err := c.objectStorage.GetRecord(ctx, c.jetID, c.id) 286 c.check(t, err) 287 } 288 289 type dropCase struct { 290 cleanCase 291 dropStorage storage.DropStorage 292 } 293 294 func (c dropCase) Check(ctx context.Context, t *testing.T) { 295 _, err := c.dropStorage.GetDrop(ctx, c.jetID, c.pulseNum) 296 c.check(t, err) 297 }