1
0
Fork 0
mirror of https://github.com/anyproto/any-sync.git synced 2025-06-08 05:57:03 +09:00
any-sync/consensus/stream/service_test.go
2022-10-20 14:04:59 +03:00

217 lines
4.9 KiB
Go

package stream
import (
"context"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app"
"github.com/anytypeio/go-anytype-infrastructure-experiments/consensus"
"github.com/anytypeio/go-anytype-infrastructure-experiments/consensus/consensusproto/consensuserr"
"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_NewStream(t *testing.T) {
t.Run("watch/unwatch", func(t *testing.T) {
fx := newFixture(t)
defer fx.Finish(t)
var expLogId = []byte("logId")
var preloadLogId = []byte("preloadId")
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
}
fx.mockDB.receiver(preloadLogId, []consensus.Record{
{
Id: []byte{'2'},
PrevId: []byte{'1'},
},
{
Id: []byte{'1'},
},
})
st1 := fx.NewStream()
sr1 := readStream(st1)
assert.Equal(t, uint64(1), sr1.id)
st1.WatchIds(ctx, [][]byte{expLogId, preloadLogId})
st1.UnwatchIds(ctx, [][]byte{preloadLogId})
assert.Equal(t, [][]byte{expLogId}, st1.LogIds())
st2 := fx.NewStream()
sr2 := readStream(st2)
assert.Equal(t, uint64(2), sr2.id)
st2.WatchIds(ctx, [][]byte{expLogId, preloadLogId})
fx.mockDB.receiver(expLogId, []consensus.Record{
{
Id: []byte{'1'},
},
})
fx.mockDB.receiver(expLogId, []consensus.Record{
{
Id: []byte{'2'},
PrevId: []byte{'1'},
},
{
Id: []byte{'1'},
},
})
fx.mockDB.receiver(preloadLogId, []consensus.Record{
{
Id: []byte{'3'},
PrevId: []byte{'4'},
},
{
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.Len(t, sr1.logs, 2)
assert.Len(t, sr1.logs[string(expLogId)].Records, 2)
assert.Equal(t, []byte{'2'}, sr1.logs[string(expLogId)].Records[0].Id)
assert.Equal(t, []byte{'2'}, sr1.logs[string(preloadLogId)].Records[0].Id)
require.Len(t, sr2.logs, 2)
assert.Len(t, sr2.logs[string(expLogId)].Records, 2)
assert.Equal(t, []byte{'2'}, sr2.logs[string(expLogId)].Records[0].Id)
assert.Equal(t, []byte{'3'}, sr2.logs[string(preloadLogId)].Records[0].Id)
})
t.Run("error", func(t *testing.T) {
fx := newFixture(t)
defer fx.Finish(t)
fx.mockDB.fetchLog = func(ctx context.Context, logId []byte) (log consensus.Log, err error) {
return log, consensuserr.ErrLogNotFound
}
st1 := fx.NewStream()
sr1 := readStream(st1)
id := []byte("nonExists")
assert.Equal(t, uint64(1), sr1.id)
st1.WatchIds(ctx, [][]byte{id})
st1.Close()
<-sr1.finished
require.Len(t, sr1.logs, 1)
assert.Equal(t, consensuserr.ErrLogNotFound, sr1.logs[string(id)].Err)
})
}
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.id,
stream: st,
logs: map[string]consensus.Log{},
finished: make(chan struct{}),
}
go sr.read()
return sr
}
type streamReader struct {
id uint64
stream *Stream
logs map[string]consensus.Log
finished chan struct{}
}
func (sr *streamReader) read() {
defer close(sr.finished)
for {
logs := sr.stream.WaitLogs()
if len(logs) == 0 {
return
}
for _, l := range logs {
if el, ok := sr.logs[string(l.Id)]; !ok {
sr.logs[string(l.Id)] = l
} else {
el.Records = append(l.Records, el.Records...)
sr.logs[string(l.Id)] = el
}
}
}
}
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
}