mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-10-14 00:59:33 +00:00
[NOD-922] Panic from cursor Next and First (#703)
* [NOD-922] Panic in Cursor First and Next if the cursor is closed. * [NOD-922] Fix broken tests. * [NOD-922] Fix a comment.
This commit is contained in:
parent
5fe9dae557
commit
3af945692e
@ -3,11 +3,11 @@ package database
|
|||||||
// Cursor iterates over database entries given some bucket.
|
// Cursor iterates over database entries given some bucket.
|
||||||
type Cursor interface {
|
type Cursor interface {
|
||||||
// Next moves the iterator to the next key/value pair. It returns whether the
|
// Next moves the iterator to the next key/value pair. It returns whether the
|
||||||
// iterator is exhausted. Returns false if the cursor is closed.
|
// iterator is exhausted. Panics if the cursor is closed.
|
||||||
Next() bool
|
Next() bool
|
||||||
|
|
||||||
// First moves the iterator to the first key/value pair. It returns false if
|
// First moves the iterator to the first key/value pair. It returns false if
|
||||||
// such a pair does not exist or if the cursor is closed.
|
// such a pair does not exist. Panics if the cursor is closed.
|
||||||
First() bool
|
First() bool
|
||||||
|
|
||||||
// Seek moves the iterator to the first key/value pair whose key is greater
|
// Seek moves the iterator to the first key/value pair whose key is greater
|
||||||
|
@ -7,6 +7,7 @@ package database_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"github.com/kaspanet/kaspad/database"
|
"github.com/kaspanet/kaspad/database"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
@ -23,6 +24,20 @@ func prepareCursorForTest(t *testing.T, db database.Database, testName string) d
|
|||||||
return cursor
|
return cursor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func recoverFromClosedCursorPanic(t *testing.T, testName string) {
|
||||||
|
panicErr := recover()
|
||||||
|
if panicErr == nil {
|
||||||
|
t.Fatalf("%s: cursor unexpectedly "+
|
||||||
|
"didn't panic after being closed", testName)
|
||||||
|
}
|
||||||
|
expectedPanicErr := "closed cursor"
|
||||||
|
if !strings.Contains(fmt.Sprintf("%v", panicErr), expectedPanicErr) {
|
||||||
|
t.Fatalf("%s: cursor panicked "+
|
||||||
|
"with wrong message. Want: %v, got: %s",
|
||||||
|
testName, expectedPanicErr, panicErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCursorNext(t *testing.T) {
|
func TestCursorNext(t *testing.T) {
|
||||||
testForAllDatabaseTypes(t, "TestCursorNext", testCursorNext)
|
testForAllDatabaseTypes(t, "TestCursorNext", testCursorNext)
|
||||||
}
|
}
|
||||||
@ -67,19 +82,20 @@ func testCursorNext(t *testing.T, db database.Database, testName string) {
|
|||||||
"not done", testName)
|
"not done", testName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rewind the cursor, close it, and call Next on it again.
|
// Rewind the cursor and close it
|
||||||
// This time it should return false because it's closed.
|
|
||||||
cursor.First()
|
cursor.First()
|
||||||
err := cursor.Close()
|
err := cursor.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s: Close unexpectedly "+
|
t.Fatalf("%s: Close unexpectedly "+
|
||||||
"failed: %s", testName, err)
|
"failed: %s", testName, err)
|
||||||
}
|
}
|
||||||
hasNext = cursor.Next()
|
|
||||||
if hasNext {
|
// Call Next on the cursor. This time it should panic
|
||||||
t.Fatalf("%s: cursor unexpectedly "+
|
// because it's closed.
|
||||||
"returned true after being closed", testName)
|
func() {
|
||||||
}
|
defer recoverFromClosedCursorPanic(t, testName)
|
||||||
|
cursor.Next()
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCursorFirst(t *testing.T) {
|
func TestCursorFirst(t *testing.T) {
|
||||||
@ -315,17 +331,15 @@ func testCursorCloseFirstAndNext(t *testing.T, db database.Database, testName st
|
|||||||
"unexpectedly failed: %s", testName, err)
|
"unexpectedly failed: %s", testName, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// We expect First to return false
|
// We expect First to panic
|
||||||
result := cursor.First()
|
func() {
|
||||||
if result {
|
defer recoverFromClosedCursorPanic(t, testName)
|
||||||
t.Fatalf("%s: First "+
|
cursor.First()
|
||||||
"unexpectedly returned true", testName)
|
}()
|
||||||
}
|
|
||||||
|
|
||||||
// We expect Next to return false
|
// We expect Next to panic
|
||||||
result = cursor.Next()
|
func() {
|
||||||
if result {
|
defer recoverFromClosedCursorPanic(t, testName)
|
||||||
t.Fatalf("%s: Next "+
|
cursor.Next()
|
||||||
"unexpectedly returned true", testName)
|
}()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -27,19 +27,19 @@ func (db *LevelDB) Cursor(bucket *database.Bucket) *LevelDBCursor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Next moves the iterator to the next key/value pair. It returns whether the
|
// Next moves the iterator to the next key/value pair. It returns whether the
|
||||||
// iterator is exhausted. Returns false if the cursor is closed.
|
// iterator is exhausted. Panics if the cursor is closed.
|
||||||
func (c *LevelDBCursor) Next() bool {
|
func (c *LevelDBCursor) Next() bool {
|
||||||
if c.isClosed {
|
if c.isClosed {
|
||||||
return false
|
panic("cannot call next on a closed cursor")
|
||||||
}
|
}
|
||||||
return c.ldbIterator.Next()
|
return c.ldbIterator.Next()
|
||||||
}
|
}
|
||||||
|
|
||||||
// First moves the iterator to the first key/value pair. It returns false if
|
// First moves the iterator to the first key/value pair. It returns false if
|
||||||
// such a pair does not exist or if the cursor is closed.
|
// such a pair does not exist. Panics if the cursor is closed.
|
||||||
func (c *LevelDBCursor) First() bool {
|
func (c *LevelDBCursor) First() bool {
|
||||||
if c.isClosed {
|
if c.isClosed {
|
||||||
return false
|
panic("cannot call first on a closed cursor")
|
||||||
}
|
}
|
||||||
return c.ldbIterator.First()
|
return c.ldbIterator.First()
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user