You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
217 lines
4.0 KiB
217 lines
4.0 KiB
package pool_test |
|
|
|
import ( |
|
"bytes" |
|
"testing" |
|
"time" |
|
|
|
"github.com/lightningnetwork/lnd/buffer" |
|
"github.com/lightningnetwork/lnd/pool" |
|
) |
|
|
|
type mockRecycler bool |
|
|
|
func (m *mockRecycler) Recycle() { |
|
*m = false |
|
} |
|
|
|
// TestRecyclers verifies that known recyclable types properly return to their |
|
// zero-value after invoking Recycle. |
|
func TestRecyclers(t *testing.T) { |
|
tests := []struct { |
|
name string |
|
newItem func() interface{} |
|
}{ |
|
{ |
|
"mock recycler", |
|
func() interface{} { return new(mockRecycler) }, |
|
}, |
|
{ |
|
"write_buffer", |
|
func() interface{} { return new(buffer.Write) }, |
|
}, |
|
{ |
|
"read_buffer", |
|
func() interface{} { return new(buffer.Read) }, |
|
}, |
|
} |
|
|
|
for _, test := range tests { |
|
t.Run(test.name, func(t *testing.T) { |
|
// Initialize the Recycler to test. |
|
r := test.newItem().(pool.Recycler) |
|
|
|
// Dirty the item. |
|
dirtyGeneric(t, r) |
|
|
|
// Invoke Recycle to clear the item. |
|
r.Recycle() |
|
|
|
// Assert the item is now clean. |
|
isCleanGeneric(t, r) |
|
}) |
|
} |
|
} |
|
|
|
type recyclePoolTest struct { |
|
name string |
|
newPool func() interface{} |
|
} |
|
|
|
// TestGenericRecyclePoolTests generically tests that pools derived from the |
|
// base Recycle pool properly are properly configured. |
|
func TestConcreteRecyclePoolTests(t *testing.T) { |
|
const ( |
|
gcInterval = time.Second |
|
expiryInterval = 250 * time.Millisecond |
|
) |
|
|
|
tests := []recyclePoolTest{ |
|
{ |
|
name: "write buffer pool", |
|
newPool: func() interface{} { |
|
return pool.NewWriteBuffer( |
|
gcInterval, expiryInterval, |
|
) |
|
}, |
|
}, |
|
{ |
|
name: "read buffer pool", |
|
newPool: func() interface{} { |
|
return pool.NewReadBuffer( |
|
gcInterval, expiryInterval, |
|
) |
|
}, |
|
}, |
|
} |
|
|
|
for _, test := range tests { |
|
t.Run(test.name, func(t *testing.T) { |
|
testRecyclePool(t, test) |
|
}) |
|
} |
|
} |
|
|
|
func testRecyclePool(t *testing.T, test recyclePoolTest) { |
|
p := test.newPool() |
|
|
|
// Take an item from the pool. |
|
r1 := takeGeneric(t, p) |
|
|
|
// Dirty the item. |
|
dirtyGeneric(t, r1) |
|
|
|
// Return the item to the pool. |
|
returnGeneric(t, p, r1) |
|
|
|
// Take items from the pool until we find the original. We expect at |
|
// most two, in the event that a fresh item is populated after the |
|
// first is taken. |
|
for i := 0; i < 2; i++ { |
|
// Wait a small duration to ensure the tests are reliable, and |
|
// don't to active the non-blocking case unintentionally. |
|
<-time.After(time.Millisecond) |
|
|
|
r2 := takeGeneric(t, p) |
|
|
|
// Take an item, skipping those whose pointer does not match the |
|
// one we dirtied. |
|
if r1 != r2 { |
|
continue |
|
} |
|
|
|
// Finally, verify that the item has been properly cleaned. |
|
isCleanGeneric(t, r2) |
|
|
|
return |
|
} |
|
|
|
t.Fatalf("original item not found") |
|
} |
|
|
|
func takeGeneric(t *testing.T, p interface{}) pool.Recycler { |
|
t.Helper() |
|
|
|
switch pp := p.(type) { |
|
case *pool.WriteBuffer: |
|
return pp.Take() |
|
|
|
case *pool.ReadBuffer: |
|
return pp.Take() |
|
|
|
default: |
|
t.Fatalf("unknown pool type: %T", p) |
|
} |
|
|
|
return nil |
|
} |
|
|
|
func returnGeneric(t *testing.T, p, item interface{}) { |
|
t.Helper() |
|
|
|
switch pp := p.(type) { |
|
case *pool.WriteBuffer: |
|
pp.Return(item.(*buffer.Write)) |
|
|
|
case *pool.ReadBuffer: |
|
pp.Return(item.(*buffer.Read)) |
|
|
|
default: |
|
t.Fatalf("unknown pool type: %T", p) |
|
} |
|
} |
|
|
|
func dirtyGeneric(t *testing.T, i interface{}) { |
|
t.Helper() |
|
|
|
switch item := i.(type) { |
|
case *mockRecycler: |
|
*item = true |
|
|
|
case *buffer.Write: |
|
dirtySlice(item[:]) |
|
|
|
case *buffer.Read: |
|
dirtySlice(item[:]) |
|
|
|
default: |
|
t.Fatalf("unknown item type: %T", i) |
|
} |
|
|
|
} |
|
|
|
func dirtySlice(slice []byte) { |
|
for i := range slice { |
|
slice[i] = 0xff |
|
} |
|
} |
|
|
|
func isCleanGeneric(t *testing.T, i interface{}) { |
|
t.Helper() |
|
|
|
switch item := i.(type) { |
|
case *mockRecycler: |
|
if isDirty := *item; isDirty { |
|
t.Fatalf("mock recycler still diry") |
|
} |
|
|
|
case *buffer.Write: |
|
isCleanSlice(t, item[:]) |
|
|
|
case *buffer.Read: |
|
isCleanSlice(t, item[:]) |
|
|
|
default: |
|
t.Fatalf("unknown item type: %T", i) |
|
} |
|
} |
|
|
|
func isCleanSlice(t *testing.T, slice []byte) { |
|
t.Helper() |
|
|
|
expSlice := make([]byte, len(slice)) |
|
if !bytes.Equal(expSlice, slice) { |
|
t.Fatalf("slice not recycled, want: %v, got: %v", |
|
expSlice, slice) |
|
} |
|
}
|
|
|