any-sync/consensus/stream/service_test.go
Sergey Cherepanov 7f0960937e
consensus node
2022-10-04 15:39:29 +03:00

170 lines
3.4 KiB
Go

package stream
import (
"context"
"github.com/anytypeio/go-anytype-infrastructure-experiments/app"
"github.com/anytypeio/go-anytype-infrastructure-experiments/consensus"
"github.com/anytypeio/go-anytype-infrastructure-experiments/consensus/db"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"testing"
"time"
)
var ctx = context.Background()
func TestService_Subscribe(t *testing.T) {
fx := newFixture(t)
defer fx.Finish(t)
var expLogId = []byte("logId")
fx.mockDB.fetchLog = func(ctx context.Context, logId []byte) (log consensus.Log, err error) {
require.Equal(t, expLogId, logId)
return consensus.Log{
Id: logId,
Records: []consensus.Record{
{
Id: []byte{'1'},
},
},
}, nil
}
st1, err := fx.Subscribe(ctx, expLogId)
require.NoError(t, err)
require.Equal(t, expLogId, st1.LogId())
sr1 := readStream(st1)
assert.Equal(t, uint32(1), sr1.id)
st2, err := fx.Subscribe(ctx, expLogId)
require.NoError(t, err)
require.Equal(t, expLogId, st2.LogId())
sr2 := readStream(st2)
assert.Equal(t, uint32(2), sr2.id)
fx.mockDB.receiver(expLogId, []consensus.Record{
{
Id: []byte{'1'},
},
})
fx.mockDB.receiver([]byte("other id"), []consensus.Record{
{
Id: []byte{'2'},
PrevId: []byte{'1'},
},
{
Id: []byte{'1'},
},
})
fx.mockDB.receiver(expLogId, []consensus.Record{
{
Id: []byte{'2'},
PrevId: []byte{'1'},
},
{
Id: []byte{'1'},
},
})
st1.Close()
st2.Close()
for _, sr := range []*streamReader{sr1, sr2} {
select {
case <-time.After(time.Second / 3):
require.False(t, true, "timeout")
case <-sr.finished:
}
}
require.Equal(t, sr1.records, sr2.records)
require.Len(t, sr1.records, 1)
assert.Equal(t, []byte{'2'}, sr1.records[0].Id)
}
func newFixture(t *testing.T) *fixture {
fx := &fixture{
Service: New(),
mockDB: &mockDB{},
a: new(app.App),
}
fx.a.Register(fx.Service).Register(fx.mockDB)
require.NoError(t, fx.a.Start(ctx))
return fx
}
type fixture struct {
Service
mockDB *mockDB
a *app.App
}
func (fx *fixture) Finish(t *testing.T) {
require.NoError(t, fx.a.Close(ctx))
}
func readStream(st Stream) *streamReader {
sr := &streamReader{
id: st.(*stream).id,
stream: st,
finished: make(chan struct{}),
}
go sr.read()
return sr
}
type streamReader struct {
id uint32
stream Stream
records []consensus.Record
finished chan struct{}
}
func (sr *streamReader) read() {
defer close(sr.finished)
for {
records := sr.stream.WaitRecords()
if len(records) == 0 {
return
}
sr.records = append(sr.records, records...)
}
}
type mockDB struct {
receiver db.ChangeReceiver
fetchLog func(ctx context.Context, logId []byte) (log consensus.Log, err error)
}
func (m *mockDB) AddLog(ctx context.Context, log consensus.Log) (err error) { return nil }
func (m *mockDB) AddRecord(ctx context.Context, logId []byte, record consensus.Record) (err error) {
return nil
}
func (m *mockDB) FetchLog(ctx context.Context, logId []byte) (log consensus.Log, err error) {
return m.fetchLog(ctx, logId)
}
func (m *mockDB) SetChangeReceiver(receiver db.ChangeReceiver) (err error) {
m.receiver = receiver
return nil
}
func (m *mockDB) Init(a *app.App) (err error) {
return nil
}
func (m *mockDB) Name() (name string) {
return db.CName
}
func (m *mockDB) Run(ctx context.Context) (err error) {
return
}
func (m *mockDB) Close(ctx context.Context) (err error) {
return
}