erigon-pulse/ethdb/remote/bolt_remote_test.go
Alex Sharov c5ffc971c5
[WIP] Badger v2 (#378)
* badger v2 investigation

* buf pool - use native New method and avoid double checks

* db.Open prototype

* db.Tx/Bucket/Cursor prototypes

* Chained config

* Item concept added

* save changes to test on master

* make hack resumable

* Design document v0

* Cursor concept

* less brackets syntax of cursor builder

* benchmarks

* cleanup fs

* test for context cancelations

* test for context cancelations

* test for cursor.Prefix option

* add ForEachKey method

* add ForEachKey method

* add naming explanation

* experiment of non-pointers cursor/bucket

* .Bucket() and .Cursor() doesn't returns error

* .Bucket() and .Cursor() doesn't returns error

* .Bucket() and .Cursor() doesn't returns error

* remove CursorOpts concept

* more test-cases

* simplify open api

* Tx, Bucket, Cursor - now are interfaces

* Tx, Bucket, Cursor - now are interfaces

* switch to interfaces

* rebase master

Co-authored-by: alex.sharov <alex.sharov@lazada.com>
2020-03-11 11:02:37 +00:00

81 lines
2.1 KiB
Go

package remote
import (
"bytes"
"context"
"io"
"net"
"testing"
"time"
"github.com/ledgerwatch/turbo-geth/ethdb/codecpool"
"github.com/stretchr/testify/assert"
)
func TestReconnect(t *testing.T) {
assert := assert.New(t)
// Prepare input buffer with one command CmdVersion
var inBuf bytes.Buffer
encoder := codecpool.Encoder(&inBuf)
defer codecpool.Return(encoder)
// output buffer to receive the result of the command
var outBuf bytes.Buffer
decoder := codecpool.Decoder(&outBuf)
defer codecpool.Return(decoder)
dialCallCounter := 0
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
pingCh := make(chan time.Time, ClientMaxConnections)
opts := DefaultOpts
opts.DialFunc = func(ctx context.Context) (in io.Reader, out io.Writer, closer io.Closer, err error) {
dialCallCounter++
if dialCallCounter%2 == 0 {
return &inBuf, &outBuf, nil, net.UnknownNetworkError("Oops")
}
return &inBuf, &outBuf, nil, nil
}
db := &DB{
opts: opts,
connectionPool: make(chan *conn, ClientMaxConnections),
doDial: make(chan struct{}, ClientMaxConnections),
doPing: pingCh,
}
// no open connections by default
assert.Equal(0, dialCallCounter)
assert.Equal(0, len(db.connectionPool))
// open 1 connection and wait for it
db.doDial <- struct{}{}
db.autoReconnect(ctx)
<-db.connectionPool
assert.Equal(1, dialCallCounter)
assert.Equal(0, len(db.connectionPool))
// open 2nd connection - dialFunc will return err on 2nd call, but db must reconnect automatically
db.doDial <- struct{}{}
db.autoReconnect(ctx) // dial err
db.autoReconnect(ctx) // dial ok
<-db.connectionPool
assert.Equal(3, dialCallCounter)
assert.Equal(0, len(db.connectionPool))
// open conn and call ping on it
db.doDial <- struct{}{}
assert.Nil(encoder.Encode(ResponseOk))
assert.Nil(encoder.Encode(Version))
db.autoReconnect(ctx) // dial err
db.autoReconnect(ctx) // dial ok
assert.Equal(5, dialCallCounter)
assert.Equal(1, len(db.connectionPool))
pingCh <- time.Now()
db.autoReconnect(ctx)
var cmd Command
assert.Nil(decoder.Decode(&cmd))
assert.Equal(CmdVersion, cmd)
// TODO: cover case when ping receive io.EOF
}