package nodeconf import ( "context" "errors" "sync" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/anyproto/any-sync/app" "github.com/anyproto/any-sync/net" "github.com/anyproto/any-sync/net/secureservice/handshake" "github.com/anyproto/any-sync/testutil/accounttest" ) var ctx = context.Background() func TestService_NetworkCompatibilityStatus(t *testing.T) { t.Run("unknown", func(t *testing.T) { fx := newFixture(t) defer fx.finish(t) fx.testSource.call = func() (c Configuration, e error) { e = net.ErrUnableToConnect return } fx.run(t) time.Sleep(time.Millisecond * 10) assert.Equal(t, NetworkCompatibilityStatusUnknown, fx.NetworkCompatibilityStatus()) }) t.Run("incompatible", func(t *testing.T) { fx := newFixture(t) defer fx.finish(t) fx.testSource.err = handshake.ErrIncompatibleVersion fx.run(t) time.Sleep(time.Millisecond * 10) assert.Equal(t, NetworkCompatibilityStatusIncompatible, fx.NetworkCompatibilityStatus()) }) t.Run("error", func(t *testing.T) { fx := newFixture(t) defer fx.finish(t) fx.testSource.call = func() (c Configuration, e error) { e = errors.New("some error") return } fx.run(t) time.Sleep(time.Millisecond * 10) assert.Equal(t, NetworkCompatibilityStatusError, fx.NetworkCompatibilityStatus()) }) t.Run("ok", func(t *testing.T) { fx := newFixture(t) defer fx.finish(t) fx.run(t) time.Sleep(time.Millisecond * 10) assert.Equal(t, NetworkCompatibilityStatusOk, fx.NetworkCompatibilityStatus()) }) t.Run("needs update", func(t *testing.T) { fx := newFixture(t) fx.testCoordinator.needsUpdate = true defer fx.finish(t) fx.run(t) time.Sleep(time.Millisecond * 10) assert.Equal(t, NetworkCompatibilityStatusNeedsUpdate, fx.NetworkCompatibilityStatus()) }) t.Run("network not changed update", func(t *testing.T) { fx := newFixture(t) fx.testSource.err = ErrConfigurationNotChanged defer fx.finish(t) fx.run(t) time.Sleep(time.Millisecond * 10) assert.Equal(t, NetworkCompatibilityStatusOk, fx.NetworkCompatibilityStatus()) }) } func TestService_NetworkGetLast(t *testing.T) { t.Run("same configuration error does not cause empty one to be set", func(t *testing.T) { fx := newFixture(t) fx.testSource.call = func() (Configuration, error) { return Configuration{}, ErrConfigurationNotChanged } defer fx.finish(t) fx.run(t) time.Sleep(time.Millisecond * 10) assert.NotEmpty(t, fx.Configuration().Id) }) } func newFixture(t *testing.T) *fixture { fx := &fixture{ Service: New(), testCoordinator: &testCoordinator{}, a: new(app.App), testStore: &testStore{}, testSource: &testSource{}, testConf: newTestConf(), } fx.a.Register(fx.testConf).Register(&accounttest.AccountTestService{}).Register(fx.Service).Register(fx.testSource).Register(fx.testStore).Register(fx.testCoordinator) return fx } type fixture struct { Service a *app.App testStore *testStore testSource *testSource testConf *testConf testCoordinator *testCoordinator } func (fx *fixture) run(t *testing.T) { require.NoError(t, fx.a.Start(ctx)) } func (fx *fixture) finish(t *testing.T) { require.NoError(t, fx.a.Close(ctx)) } type testCoordinator struct { needsUpdate bool } func (t *testCoordinator) IsNetworkNeedsUpdate(ctx context.Context) (bool, error) { return t.needsUpdate, nil } func (t *testCoordinator) Init(a *app.App) error { return nil } func (t *testCoordinator) Name() string { return "testCoordinator" } type testSource struct { conf Configuration err error call func() (Configuration, error) } func (t *testSource) Init(a *app.App) error { return nil } func (t *testSource) Name() string { return CNameSource } func (t *testSource) GetLast(ctx context.Context, currentId string) (c Configuration, err error) { if t.call != nil { return t.call() } return t.conf, t.err } type testStore struct { conf *Configuration mu sync.Mutex } func (t *testStore) Init(a *app.App) error { return nil } func (t *testStore) Name() string { return CNameStore } func (t *testStore) GetLast(ctx context.Context, netId string) (c Configuration, err error) { t.mu.Lock() defer t.mu.Unlock() if t.conf != nil { return *t.conf, nil } else { err = ErrConfigurationNotFound } return } func (t *testStore) SaveLast(ctx context.Context, c Configuration) (err error) { t.mu.Lock() defer t.mu.Unlock() t.conf = &c return } type testConf struct { Configuration } func (t *testConf) Init(a *app.App) error { return nil } func (t *testConf) Name() string { return "config" } func (t *testConf) GetNodeConf() Configuration { return t.Configuration } func newTestConf() *testConf { return &testConf{ Configuration{ Id: "test", NetworkId: "testNetwork", Nodes: []Node{ { PeerId: "12D3KooWKLCajM89S8unbt3tgGbRLgmiWnFZT3adn9A5pQciBSLa", Addresses: []string{"127.0.0.1:4830"}, Types: []NodeType{NodeTypeCoordinator}, }, { PeerId: "12D3KooWKnXTtbveMDUFfeSqR5dt9a4JW66tZQXG7C7PdDh3vqGu", Addresses: []string{"127.0.0.1:4730"}, Types: []NodeType{NodeTypeTree}, }, { PeerId: "12D3KooWKgVN2kW8xw5Uvm2sLUnkeUNQYAvcWvF58maTzev7FjPi", Addresses: []string{"127.0.0.1:4731"}, Types: []NodeType{NodeTypeTree}, }, { PeerId: "12D3KooWCUPYuMnQhu9yREJgQyjcz8zWY83rZGmDLwb9YR6QkbZX", Addresses: []string{"127.0.0.1:4732"}, Types: []NodeType{NodeTypeTree}, }, { PeerId: "12D3KooWQxiZ5a7vcy4DTJa8Gy1eVUmwb5ojN4SrJC9Rjxzigw6C", Addresses: []string{"127.0.0.1:4733"}, Types: []NodeType{NodeTypeFile}, }, }, CreationTime: time.Now(), }, } } func TestService_mergeCoordinatorAddrs(t *testing.T) { t.Run("coorditor nodes with different peerID added", func(t *testing.T) { confApp := Configuration{ Id: "test", NetworkId: "testNetwork", Nodes: []Node{ { PeerId: "12D3KooWKgVN2kW8xw5Uvm2sLUnkeUNQYAvcWvF58maTzev7FjPi", Addresses: []string{"127.0.0.1:3030", "192.168.1.1:8833"}, Types: []NodeType{NodeTypeCoordinator}, }, }, CreationTime: time.Now(), } confStored := Configuration{ Id: "test", NetworkId: "testNetwork", Nodes: []Node{ { PeerId: "12D3KooWKLCajM89S8unbt3tgGbRLgmiWnFZT3adn9A5pQciBSLa", Addresses: []string{"127.0.0.1:4830"}, Types: []NodeType{NodeTypeCoordinator}, }, }, CreationTime: time.Now(), } mergeCoordinatorAddrs(&confApp, &confStored) assert.Equal(t, 2, len(confStored.Nodes)) assert.Equal(t, "127.0.0.1:3030", confStored.Nodes[1].Addresses[0]) assert.Equal(t, "192.168.1.1:8833", confStored.Nodes[1].Addresses[1]) assert.Equal(t, "12D3KooWKgVN2kW8xw5Uvm2sLUnkeUNQYAvcWvF58maTzev7FjPi", confStored.Nodes[1].PeerId) }) t.Run("coorditor nodes with the same peerID have Addresses merged", func(t *testing.T) { confApp := Configuration{ Id: "test", NetworkId: "testNetwork", Nodes: []Node{ { PeerId: "12D3KooWKLCajM89S8unbt3tgGbRLgmiWnFZT3adn9A5pQciBSLa", Addresses: []string{"127.0.0.1:4830", "192.168.1.1:8833"}, Types: []NodeType{NodeTypeCoordinator}, }, }, CreationTime: time.Now(), } confStored := Configuration{ Id: "test", NetworkId: "testNetwork", Nodes: []Node{ { PeerId: "12D3KooWKLCajM89S8unbt3tgGbRLgmiWnFZT3adn9A5pQciBSLa", Addresses: []string{"127.0.0.1:4830"}, Types: []NodeType{NodeTypeCoordinator}, }, }, CreationTime: time.Now(), } mergeCoordinatorAddrs(&confApp, &confStored) assert.Equal(t, 2, len(confStored.Nodes[0].Addresses)) assert.Equal(t, "127.0.0.1:4830", confStored.Nodes[0].Addresses[0]) assert.Equal(t, "192.168.1.1:8833", confStored.Nodes[0].Addresses[1]) }) }