Skip to content

Commit 5d96aff

Browse files
authored
refactor(ffi/iterator): move tests into a separate file (#1543)
## Why this should be merged As discussed with @alarso16 before, this moves the iterator-related tests into a separate file to keep things organized. ## How this works Moves iterator-related tests out of `firewood_test.go` into their own file. ## How this was tested Existing go tests. ## Need to be documented in RELEASES.md? N/A
1 parent f11d149 commit 5d96aff

File tree

2 files changed

+326
-315
lines changed

2 files changed

+326
-315
lines changed

ffi/firewood_test.go

Lines changed: 0 additions & 315 deletions
Original file line numberDiff line numberDiff line change
@@ -1296,321 +1296,6 @@ func TestFjallStore(t *testing.T) {
12961296
}
12971297
}
12981298

1299-
type kvIter interface {
1300-
SetBatchSize(int)
1301-
Next() bool
1302-
Key() []byte
1303-
Value() []byte
1304-
Err() error
1305-
Drop() error
1306-
}
1307-
type borrowIter struct{ it *Iterator }
1308-
1309-
func (b *borrowIter) SetBatchSize(batchSize int) { b.it.SetBatchSize(batchSize) }
1310-
func (b *borrowIter) Next() bool { return b.it.NextBorrowed() }
1311-
func (b *borrowIter) Key() []byte { return b.it.Key() }
1312-
func (b *borrowIter) Value() []byte { return b.it.Value() }
1313-
func (b *borrowIter) Err() error { return b.it.Err() }
1314-
func (b *borrowIter) Drop() error { return b.it.Drop() }
1315-
1316-
func assertIteratorYields(r *require.Assertions, it kvIter, keys [][]byte, vals [][]byte) {
1317-
i := 0
1318-
for ; it.Next(); i += 1 {
1319-
r.Equal(keys[i], it.Key())
1320-
r.Equal(vals[i], it.Value())
1321-
}
1322-
r.NoError(it.Err())
1323-
r.Equal(len(keys), i)
1324-
}
1325-
1326-
type iteratorConfigFn = func(it kvIter) kvIter
1327-
1328-
var iterConfigs = map[string]iteratorConfigFn{
1329-
"Owned": func(it kvIter) kvIter { return it },
1330-
"Borrowed": func(it kvIter) kvIter { return &borrowIter{it: it.(*Iterator)} },
1331-
"Single": func(it kvIter) kvIter {
1332-
it.SetBatchSize(1)
1333-
return it
1334-
},
1335-
"Batched": func(it kvIter) kvIter {
1336-
it.SetBatchSize(100)
1337-
return it
1338-
},
1339-
}
1340-
1341-
func runIteratorTestForModes(t *testing.T, fn func(*testing.T, iteratorConfigFn), modes ...string) {
1342-
testName := strings.Join(modes, "/")
1343-
t.Run(testName, func(t *testing.T) {
1344-
r := require.New(t)
1345-
fn(t, func(it kvIter) kvIter {
1346-
for _, m := range modes {
1347-
config, ok := iterConfigs[m]
1348-
r.Truef(ok, "specified config mode %s does not exist", m)
1349-
it = config(it)
1350-
}
1351-
return it
1352-
})
1353-
})
1354-
}
1355-
1356-
func runIteratorTestForAllModes(parentT *testing.T, fn func(*testing.T, iteratorConfigFn)) {
1357-
for _, dataMode := range []string{"Owned", "Borrowed"} {
1358-
for _, batchMode := range []string{"Single", "Batched"} {
1359-
runIteratorTestForModes(parentT, fn, batchMode, dataMode)
1360-
}
1361-
}
1362-
}
1363-
1364-
// Tests that basic iterator functionality works
1365-
func TestIter(t *testing.T) {
1366-
r := require.New(t)
1367-
db := newTestDatabase(t)
1368-
keys, vals := kvForTest(100)
1369-
_, err := db.Update(keys, vals)
1370-
r.NoError(err)
1371-
1372-
runIteratorTestForAllModes(t, func(t *testing.T, cfn iteratorConfigFn) {
1373-
r := require.New(t)
1374-
rev, err := db.LatestRevision()
1375-
r.NoError(err)
1376-
it, err := rev.Iter(nil)
1377-
r.NoError(err)
1378-
t.Cleanup(func() {
1379-
r.NoError(it.Drop())
1380-
r.NoError(rev.Drop())
1381-
})
1382-
1383-
assertIteratorYields(r, cfn(it), keys, vals)
1384-
})
1385-
}
1386-
1387-
func TestIterOnRoot(t *testing.T) {
1388-
r := require.New(t)
1389-
db := newTestDatabase(t)
1390-
keys, vals := kvForTest(240)
1391-
firstRoot, err := db.Update(keys[:80], vals[:80])
1392-
r.NoError(err)
1393-
secondRoot, err := db.Update(keys[80:160], vals[80:160])
1394-
r.NoError(err)
1395-
thirdRoot, err := db.Update(keys[160:], vals[160:])
1396-
r.NoError(err)
1397-
1398-
runIteratorTestForAllModes(t, func(t *testing.T, cfn iteratorConfigFn) {
1399-
r := require.New(t)
1400-
r1, err := db.Revision(firstRoot)
1401-
r.NoError(err)
1402-
h1, err := r1.Iter(nil)
1403-
r.NoError(err)
1404-
t.Cleanup(func() {
1405-
r.NoError(h1.Drop())
1406-
r.NoError(r1.Drop())
1407-
})
1408-
1409-
r2, err := db.Revision(secondRoot)
1410-
r.NoError(err)
1411-
h2, err := r2.Iter(nil)
1412-
r.NoError(err)
1413-
t.Cleanup(func() {
1414-
r.NoError(h2.Drop())
1415-
r.NoError(r2.Drop())
1416-
})
1417-
1418-
r3, err := db.Revision(thirdRoot)
1419-
r.NoError(err)
1420-
h3, err := r3.Iter(nil)
1421-
r.NoError(err)
1422-
t.Cleanup(func() {
1423-
r.NoError(h3.Drop())
1424-
r.NoError(r3.Drop())
1425-
})
1426-
1427-
assertIteratorYields(r, cfn(h1), keys[:80], vals[:80])
1428-
assertIteratorYields(r, cfn(h2), keys[:160], vals[:160])
1429-
assertIteratorYields(r, cfn(h3), keys, vals)
1430-
})
1431-
}
1432-
1433-
func TestIterOnProposal(t *testing.T) {
1434-
r := require.New(t)
1435-
db := newTestDatabase(t)
1436-
keys, vals := kvForTest(240)
1437-
_, err := db.Update(keys, vals)
1438-
r.NoError(err)
1439-
1440-
runIteratorTestForAllModes(t, func(t *testing.T, cfn iteratorConfigFn) {
1441-
r := require.New(t)
1442-
updatedValues := make([][]byte, len(vals))
1443-
copy(updatedValues, vals)
1444-
1445-
changedKeys := make([][]byte, 0)
1446-
changedVals := make([][]byte, 0)
1447-
for i := 0; i < len(vals); i += 4 {
1448-
changedKeys = append(changedKeys, keys[i])
1449-
newVal := []byte{byte(i)}
1450-
changedVals = append(changedVals, newVal)
1451-
updatedValues[i] = newVal
1452-
}
1453-
p, err := db.Propose(changedKeys, changedVals)
1454-
r.NoError(err)
1455-
it, err := p.Iter(nil)
1456-
r.NoError(err)
1457-
t.Cleanup(func() {
1458-
r.NoError(it.Drop())
1459-
})
1460-
1461-
assertIteratorYields(r, cfn(it), keys, updatedValues)
1462-
})
1463-
}
1464-
1465-
// Tests that the iterator still works after proposal is committed
1466-
func TestIterAfterProposalCommit(t *testing.T) {
1467-
r := require.New(t)
1468-
db := newTestDatabase(t)
1469-
1470-
keys, vals := kvForTest(10)
1471-
p, err := db.Propose(keys, vals)
1472-
r.NoError(err)
1473-
1474-
it, err := p.Iter(nil)
1475-
r.NoError(err)
1476-
t.Cleanup(func() {
1477-
r.NoError(it.Drop())
1478-
})
1479-
1480-
err = p.Commit()
1481-
r.NoError(err)
1482-
1483-
// iterate after commit
1484-
// because iterator hangs on the nodestore reference of proposal
1485-
// the nodestore won't be dropped until we drop the iterator
1486-
assertIteratorYields(r, it, keys, vals)
1487-
}
1488-
1489-
// Tests that the iterator on latest revision works properly after a proposal commit
1490-
func TestIterUpdate(t *testing.T) {
1491-
r := require.New(t)
1492-
db := newTestDatabase(t)
1493-
1494-
keys, vals := kvForTest(10)
1495-
_, err := db.Update(keys, vals)
1496-
r.NoError(err)
1497-
1498-
// get an iterator on latest revision
1499-
rev, err := db.LatestRevision()
1500-
r.NoError(err)
1501-
it, err := rev.Iter(nil)
1502-
r.NoError(err)
1503-
t.Cleanup(func() {
1504-
r.NoError(it.Drop())
1505-
r.NoError(rev.Drop())
1506-
})
1507-
1508-
// update the database
1509-
keys2, vals2 := kvForTest(10)
1510-
_, err = db.Update(keys2, vals2)
1511-
r.NoError(err)
1512-
1513-
// iterate after commit
1514-
// because iterator is fixed on the revision hash, it should return the initial values
1515-
assertIteratorYields(r, it, keys, vals)
1516-
}
1517-
1518-
// Tests the iterator's behavior after exhaustion, should safely return empty item/batch, indicating done
1519-
func TestIterDone(t *testing.T) {
1520-
r := require.New(t)
1521-
db := newTestDatabase(t)
1522-
1523-
keys, vals := kvForTest(18)
1524-
_, err := db.Update(keys, vals)
1525-
r.NoError(err)
1526-
1527-
// get an iterator on latest revision
1528-
rev, err := db.LatestRevision()
1529-
r.NoError(err)
1530-
it, err := rev.Iter(nil)
1531-
r.NoError(err)
1532-
t.Cleanup(func() {
1533-
r.NoError(it.Drop())
1534-
r.NoError(rev.Drop())
1535-
})
1536-
// consume the iterator
1537-
assertIteratorYields(r, it, keys, vals)
1538-
// calling next again should be safe and return false
1539-
r.False(it.Next())
1540-
r.NoError(it.Err())
1541-
1542-
// get a new iterator
1543-
it2, err := rev.Iter(nil)
1544-
r.NoError(err)
1545-
// set batch size to 5
1546-
it2.SetBatchSize(5)
1547-
// consume the iterator
1548-
assertIteratorYields(r, it2, keys, vals)
1549-
// calling next again should be safe and return false
1550-
r.False(it.Next())
1551-
r.NoError(it.Err())
1552-
}
1553-
1554-
// Tests the iterator's behavior after revision is dropped, should safely
1555-
// outlive the revision as it owns a reference to the revision in Rust.
1556-
func TestIterOutlivesRevision(t *testing.T) {
1557-
r := require.New(t)
1558-
db := newTestDatabase(t, func(config *config) {
1559-
config.revisions = 2
1560-
})
1561-
1562-
keys, vals := kvForTest(30)
1563-
_, err := db.Update(keys[:10], vals[:10])
1564-
r.NoErrorf(err, "%T.Update(...)", db)
1565-
rev, err := db.LatestRevision()
1566-
r.NoErrorf(err, "%T.LatestRevision()", db)
1567-
it, err := rev.Iter(nil)
1568-
r.NoErrorf(err, "%T.Iter()", rev)
1569-
t.Cleanup(func() {
1570-
r.NoErrorf(it.Drop(), "%T.Drop()", it)
1571-
})
1572-
1573-
// Drop the revision right away to ensure reaping
1574-
r.NoErrorf(rev.Drop(), "%T.Drop()", rev)
1575-
1576-
// Commit two more times to force reaping of the first revision
1577-
_, err = db.Update(keys[10:20], vals[10:20])
1578-
r.NoErrorf(err, "%T.Update(...)", db)
1579-
_, err = db.Update(keys[20:], vals[20:])
1580-
r.NoErrorf(err, "%T.Update(...)", db)
1581-
1582-
// iterate after reaping
1583-
assertIteratorYields(r, it, keys[:10], vals[:10])
1584-
}
1585-
1586-
// Tests the iterator's behavior after proposal is dropped, should safely
1587-
// outlive the proposal as it owns a reference to the view in Rust.
1588-
func TestIterOutlivesProposal(t *testing.T) {
1589-
r := require.New(t)
1590-
db := newTestDatabase(t)
1591-
1592-
keys, vals := kvForTest(4)
1593-
p, err := db.Propose(keys[:2], vals[:2])
1594-
r.NoErrorf(err, "%T.Propose(...)", db)
1595-
1596-
it, err := p.Iter(nil)
1597-
r.NoErrorf(err, "%T.Iter()", p)
1598-
t.Cleanup(func() {
1599-
r.NoErrorf(it.Drop(), "%T.Drop()", it)
1600-
})
1601-
r.NoErrorf(p.Drop(), "%T.Drop()", p)
1602-
1603-
// This is necessary because the dropped proposal is referenced in
1604-
// the revision manager and cleanup only runs when commit is called.
1605-
// So here we create a new proposal with different keys, and commit
1606-
// to trigger cleanup of the dropped proposal.
1607-
p2, err := db.Propose(keys[2:], vals[2:])
1608-
r.NoErrorf(err, "%T.Propose(...)", db)
1609-
r.NoErrorf(p2.Commit(), "%T.Commit(...)", db)
1610-
1611-
assertIteratorYields(r, it, keys[:2], vals[:2])
1612-
}
1613-
16141299
// TestNilVsEmptyValue tests that nil values cause delete operations while
16151300
// empty []byte{} values result in inserts with empty values.
16161301
func TestNilVsEmptyValue(t *testing.T) {

0 commit comments

Comments
 (0)