github.com/amp-space/amp-sdk-go@v0.7.6/stdlib/symbol/tests/stress-test.go (about) 1 package tests 2 3 import ( 4 "bytes" 5 "errors" 6 "strconv" 7 "sync" 8 "sync/atomic" 9 "testing" 10 11 "github.com/amp-space/amp-sdk-go/stdlib/symbol" 12 ) 13 14 const kTotalEntries = 1001447 15 16 func DoTableTest(t *testing.T, totalEntries int, opener func() (symbol.Table, error)) { 17 if totalEntries == 0 { 18 totalEntries = kTotalEntries 19 } 20 21 tt := tableTester{ 22 errs: make(chan error), 23 } 24 tt.setupTestData(totalEntries) 25 26 go func() { 27 28 // 1) tortuously fill and write a table 29 table, err := opener() 30 if err != nil { 31 tt.errs <- err 32 } 33 tt.fillTable(table) 34 table.Close() 35 36 // 2) tortuously read and check the table 37 table, err = opener() 38 if err != nil { 39 tt.errs <- err 40 } 41 tt.checkTable(table) 42 table.Close() 43 44 close(tt.errs) 45 }() 46 47 // wait for test to finish, fail the test on any errors 48 err := <-tt.errs 49 if err != nil { 50 t.Fatal(err) 51 } 52 } 53 54 type tableTester struct { 55 errs chan error 56 vals [][]byte 57 IDs []symbol.ID 58 } 59 60 func (tt *tableTester) setupTestData(totalEntries int) { 61 if len(tt.vals) != totalEntries { 62 tt.vals = make([][]byte, totalEntries) 63 for i := range tt.vals { 64 tt.vals[i] = []byte(strconv.Itoa(i)) 65 } 66 } 67 if cap(tt.IDs) < totalEntries { 68 tt.IDs = make([]symbol.ID, totalEntries) 69 } else { 70 tt.IDs = tt.IDs[:totalEntries] 71 for i := range tt.IDs { 72 tt.IDs[i] = 0 73 } 74 } 75 } 76 77 var ( 78 hardwireStart = symbol.DefaultIssuerMin - hardwireTestCount 79 hardwireTestCount = 101 80 ) 81 82 func (tt *tableTester) fillTable(table symbol.Table) { 83 vals := tt.vals 84 totalEntries := len(vals) 85 86 // Test reserved symbol ID space -- set symbol IDs less than symbol.MinIssuedID 87 // Do multiple write passes to check overwrites don't cause issues. 88 for k := 0; k < 3; k++ { 89 for j := 0; j < hardwireTestCount; j++ { 90 idx := hardwireStart + j 91 symID := symbol.ID(idx) 92 symID_got := table.SetSymbolID(vals[idx], symID) 93 if symID_got != symID { 94 tt.errs <- errors.New("SetSymbolID failed setup check") 95 } 96 } 97 } 98 99 hardwireCount := int32(0) 100 hardwireCountPtr := &hardwireCount 101 102 // Populate the table with multiple workers all setting values at once 103 { 104 running := &sync.WaitGroup{} 105 numWorkers := 5 106 for i := 0; i < numWorkers; i++ { 107 running.Add(1) 108 startAt := len(vals) * i / numWorkers 109 go func() { 110 var symBuf [128]byte 111 for j := 0; j < totalEntries; j++ { 112 idx := (startAt + j) % totalEntries 113 symID := table.GetSymbolID(vals[idx], true) 114 if symID < symbol.DefaultIssuerMin { 115 atomic.AddInt32(hardwireCountPtr, 1) 116 } 117 stored := table.GetSymbol(symID, symBuf[:0]) 118 if !bytes.Equal(stored, vals[idx]) { 119 tt.errs <- errors.New("LookupID failed setup check") 120 } 121 symID_got := table.SetSymbolID(vals[idx], symID) 122 if symID_got != symID { 123 tt.errs <- errors.New("SetSymbolID failed setup check") 124 } 125 } 126 running.Done() 127 }() 128 } 129 130 running.Wait() 131 132 if int(hardwireCount) != numWorkers*hardwireTestCount { 133 tt.errs <- errors.New("hardwire test count failed") 134 } 135 136 } 137 138 var symBuf [128]byte 139 140 // Verify all the tokens are valid 141 IDs := tt.IDs 142 for i, k := range vals { 143 IDs[i] = table.GetSymbolID(k, false) 144 if IDs[i] == 0 { 145 tt.errs <- errors.New("GetSymbolID failed final verification") 146 } 147 stored := table.GetSymbol(IDs[i], symBuf[:0]) 148 if !bytes.Equal(stored, vals[i]) { 149 tt.errs <- errors.New("LookupID failed final verification") 150 } 151 } 152 153 if table.GetSymbol(123456789, nil) != nil { 154 tt.errs <- errors.New("bad ID returns value") 155 } 156 if table.GetSymbolID([]byte{4, 5, 6, 7, 8, 9, 10, 11}, false) != 0 { 157 tt.errs <- errors.New("bad value returns ID") 158 } 159 } 160 161 func (tt *tableTester) checkTable(table symbol.Table) { 162 vals := tt.vals 163 totalEntries := len(vals) 164 165 // Check that all the tokens are present 166 { 167 IDs := tt.IDs 168 running := &sync.WaitGroup{} 169 numWorkers := 5 170 for i := 0; i < numWorkers; i++ { 171 running.Add(1) 172 startAt := len(vals) * i / numWorkers 173 go func() { 174 var symBuf [128]byte 175 for j := 0; j < totalEntries; j++ { 176 idx := (startAt + j) % totalEntries 177 178 if (j % numWorkers) == 0 { 179 symID := table.GetSymbolID(vals[idx], false) 180 if symID != IDs[idx] { 181 tt.errs <- errors.New("GetSymbolID failed readback check") 182 } 183 } else { 184 stored := table.GetSymbol(IDs[idx], symBuf[:0]) 185 if !bytes.Equal(stored, vals[idx]) { 186 tt.errs <- errors.New("LookupID failed readback check") 187 } 188 } 189 } 190 running.Done() 191 }() 192 } 193 194 running.Wait() 195 } 196 }