diff --git a/.mockery.yaml b/.mockery.yaml index 6fb1d0686..cf803d53b 100644 --- a/.mockery.yaml +++ b/.mockery.yaml @@ -145,7 +145,7 @@ packages: Space: github.com/anyproto/anytype-heart/core/anytype/config: interfaces: - Updater: + Service: github.com/anyproto/anytype-heart/core/anytype/account: interfaces: Service: diff --git a/core/anytype/config/config.go b/core/anytype/config/config.go index f0d684196..9682644f2 100644 --- a/core/anytype/config/config.go +++ b/core/anytype/config/config.go @@ -3,7 +3,8 @@ package config /* Config component provides a way to configure the application both in-memory and on-disk(see PersistedConfig). It also provides a way to set up the application with default values and to read configuration from environment variables. - If you access this config from other components, you should never modify the struct directly. Use method specified in the Updater interface + If you access this config from other components, you should never modify the struct directly. Use method specified in the ConfigModifiable interface + Fields in the root of Config struct are thread-safe for reading and should not be modified directly. */ import ( "errors" @@ -59,9 +60,11 @@ var ( ErrNetworkFileFailedToRead = fmt.Errorf("failed to read network configuration") ) -type ConfigModifiable interface { +type Service interface { + app.ComponentRunnable + // UpdatePersistentConfig updates the persistent config and writes it to the file after UpdatePersistentConfig(f func(cfg *ConfigPersistent) (updated bool)) error - Read(f func(*ConfigPersistent)) + GetPersistentConfig() ConfigPersistent } type ConfigPersistent struct { @@ -112,10 +115,10 @@ var DefaultConfig = Config{ // Read provides get specific keys values under the lock // do not use this method to modify the config -func (c *Config) Read(f func(*ConfigPersistent)) { +func (c *Config) GetPersistentConfig() ConfigPersistent { c.lock.RLock() defer c.lock.RUnlock() - f(&c.ConfigPersistent) + return c.ConfigPersistent } // UpdatePersistentConfig updates the persistent config and writes it to the file after diff --git a/core/anytype/config/mock_config/mock_Service.go b/core/anytype/config/mock_config/mock_Service.go new file mode 100644 index 000000000..c6f8a7efa --- /dev/null +++ b/core/anytype/config/mock_config/mock_Service.go @@ -0,0 +1,313 @@ +// Code generated by mockery. DO NOT EDIT. + +package mock_config + +import ( + context "context" + + app "github.com/anyproto/any-sync/app" + config "github.com/anyproto/anytype-heart/core/anytype/config" + + mock "github.com/stretchr/testify/mock" +) + +// MockService is an autogenerated mock type for the Service type +type MockService struct { + mock.Mock +} + +type MockService_Expecter struct { + mock *mock.Mock +} + +func (_m *MockService) EXPECT() *MockService_Expecter { + return &MockService_Expecter{mock: &_m.Mock} +} + +// Close provides a mock function with given fields: ctx +func (_m *MockService) Close(ctx context.Context) error { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for Close") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockService_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close' +type MockService_Close_Call struct { + *mock.Call +} + +// Close is a helper method to define mock.On call +// - ctx context.Context +func (_e *MockService_Expecter) Close(ctx interface{}) *MockService_Close_Call { + return &MockService_Close_Call{Call: _e.mock.On("Close", ctx)} +} + +func (_c *MockService_Close_Call) Run(run func(ctx context.Context)) *MockService_Close_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *MockService_Close_Call) Return(err error) *MockService_Close_Call { + _c.Call.Return(err) + return _c +} + +func (_c *MockService_Close_Call) RunAndReturn(run func(context.Context) error) *MockService_Close_Call { + _c.Call.Return(run) + return _c +} + +// GetPersistentConfig provides a mock function with given fields: +func (_m *MockService) GetPersistentConfig() config.ConfigPersistent { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetPersistentConfig") + } + + var r0 config.ConfigPersistent + if rf, ok := ret.Get(0).(func() config.ConfigPersistent); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(config.ConfigPersistent) + } + + return r0 +} + +// MockService_GetPersistentConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPersistentConfig' +type MockService_GetPersistentConfig_Call struct { + *mock.Call +} + +// GetPersistentConfig is a helper method to define mock.On call +func (_e *MockService_Expecter) GetPersistentConfig() *MockService_GetPersistentConfig_Call { + return &MockService_GetPersistentConfig_Call{Call: _e.mock.On("GetPersistentConfig")} +} + +func (_c *MockService_GetPersistentConfig_Call) Run(run func()) *MockService_GetPersistentConfig_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockService_GetPersistentConfig_Call) Return(_a0 config.ConfigPersistent) *MockService_GetPersistentConfig_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockService_GetPersistentConfig_Call) RunAndReturn(run func() config.ConfigPersistent) *MockService_GetPersistentConfig_Call { + _c.Call.Return(run) + return _c +} + +// Init provides a mock function with given fields: a +func (_m *MockService) Init(a *app.App) error { + ret := _m.Called(a) + + if len(ret) == 0 { + panic("no return value specified for Init") + } + + var r0 error + if rf, ok := ret.Get(0).(func(*app.App) error); ok { + r0 = rf(a) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockService_Init_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Init' +type MockService_Init_Call struct { + *mock.Call +} + +// Init is a helper method to define mock.On call +// - a *app.App +func (_e *MockService_Expecter) Init(a interface{}) *MockService_Init_Call { + return &MockService_Init_Call{Call: _e.mock.On("Init", a)} +} + +func (_c *MockService_Init_Call) Run(run func(a *app.App)) *MockService_Init_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*app.App)) + }) + return _c +} + +func (_c *MockService_Init_Call) Return(err error) *MockService_Init_Call { + _c.Call.Return(err) + return _c +} + +func (_c *MockService_Init_Call) RunAndReturn(run func(*app.App) error) *MockService_Init_Call { + _c.Call.Return(run) + return _c +} + +// Name provides a mock function with given fields: +func (_m *MockService) Name() string { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Name") + } + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// MockService_Name_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Name' +type MockService_Name_Call struct { + *mock.Call +} + +// Name is a helper method to define mock.On call +func (_e *MockService_Expecter) Name() *MockService_Name_Call { + return &MockService_Name_Call{Call: _e.mock.On("Name")} +} + +func (_c *MockService_Name_Call) Run(run func()) *MockService_Name_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockService_Name_Call) Return(name string) *MockService_Name_Call { + _c.Call.Return(name) + return _c +} + +func (_c *MockService_Name_Call) RunAndReturn(run func() string) *MockService_Name_Call { + _c.Call.Return(run) + return _c +} + +// Run provides a mock function with given fields: ctx +func (_m *MockService) Run(ctx context.Context) error { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for Run") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockService_Run_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Run' +type MockService_Run_Call struct { + *mock.Call +} + +// Run is a helper method to define mock.On call +// - ctx context.Context +func (_e *MockService_Expecter) Run(ctx interface{}) *MockService_Run_Call { + return &MockService_Run_Call{Call: _e.mock.On("Run", ctx)} +} + +func (_c *MockService_Run_Call) Run(run func(ctx context.Context)) *MockService_Run_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *MockService_Run_Call) Return(err error) *MockService_Run_Call { + _c.Call.Return(err) + return _c +} + +func (_c *MockService_Run_Call) RunAndReturn(run func(context.Context) error) *MockService_Run_Call { + _c.Call.Return(run) + return _c +} + +// UpdatePersistentConfig provides a mock function with given fields: f +func (_m *MockService) UpdatePersistentConfig(f func(*config.ConfigPersistent) bool) error { + ret := _m.Called(f) + + if len(ret) == 0 { + panic("no return value specified for UpdatePersistentConfig") + } + + var r0 error + if rf, ok := ret.Get(0).(func(func(*config.ConfigPersistent) bool) error); ok { + r0 = rf(f) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockService_UpdatePersistentConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdatePersistentConfig' +type MockService_UpdatePersistentConfig_Call struct { + *mock.Call +} + +// UpdatePersistentConfig is a helper method to define mock.On call +// - f func(*config.ConfigPersistent) bool +func (_e *MockService_Expecter) UpdatePersistentConfig(f interface{}) *MockService_UpdatePersistentConfig_Call { + return &MockService_UpdatePersistentConfig_Call{Call: _e.mock.On("UpdatePersistentConfig", f)} +} + +func (_c *MockService_UpdatePersistentConfig_Call) Run(run func(f func(*config.ConfigPersistent) bool)) *MockService_UpdatePersistentConfig_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(func(*config.ConfigPersistent) bool)) + }) + return _c +} + +func (_c *MockService_UpdatePersistentConfig_Call) Return(_a0 error) *MockService_UpdatePersistentConfig_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockService_UpdatePersistentConfig_Call) RunAndReturn(run func(func(*config.ConfigPersistent) bool) error) *MockService_UpdatePersistentConfig_Call { + _c.Call.Return(run) + return _c +} + +// NewMockService creates a new instance of MockService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockService(t interface { + mock.TestingT + Cleanup(func()) +}) *MockService { + mock := &MockService{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/core/anytype/config/mock_config/mock_Updater.go b/core/anytype/config/mock_config/mock_Updater.go deleted file mode 100644 index b9ef19c37..000000000 --- a/core/anytype/config/mock_config/mock_Updater.go +++ /dev/null @@ -1,81 +0,0 @@ -// Code generated by mockery. DO NOT EDIT. - -package mock_config - -import ( - config "github.com/anyproto/anytype-heart/core/anytype/config" - mock "github.com/stretchr/testify/mock" -) - -// MockUpdater is an autogenerated mock type for the Updater type -type MockUpdater struct { - mock.Mock -} - -type MockUpdater_Expecter struct { - mock *mock.Mock -} - -func (_m *MockUpdater) EXPECT() *MockUpdater_Expecter { - return &MockUpdater_Expecter{mock: &_m.Mock} -} - -// UpdatePersistentConfig provides a mock function with given fields: f -func (_m *MockUpdater) UpdatePersistentConfig(f func(*config.ConfigPersistent) bool) error { - ret := _m.Called(f) - - if len(ret) == 0 { - panic("no return value specified for UpdatePersistentConfig") - } - - var r0 error - if rf, ok := ret.Get(0).(func(func(*config.ConfigPersistent) bool) error); ok { - r0 = rf(f) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockUpdater_UpdatePersistentConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdatePersistentConfig' -type MockUpdater_UpdatePersistentConfig_Call struct { - *mock.Call -} - -// UpdatePersistentConfig is a helper method to define mock.On call -// - f func(*config.ConfigPersistent) bool -func (_e *MockUpdater_Expecter) UpdatePersistentConfig(f interface{}) *MockUpdater_UpdatePersistentConfig_Call { - return &MockUpdater_UpdatePersistentConfig_Call{Call: _e.mock.On("UpdatePersistentConfig", f)} -} - -func (_c *MockUpdater_UpdatePersistentConfig_Call) Run(run func(f func(*config.ConfigPersistent) bool)) *MockUpdater_UpdatePersistentConfig_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(func(*config.ConfigPersistent) bool)) - }) - return _c -} - -func (_c *MockUpdater_UpdatePersistentConfig_Call) Return(_a0 error) *MockUpdater_UpdatePersistentConfig_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockUpdater_UpdatePersistentConfig_Call) RunAndReturn(run func(func(*config.ConfigPersistent) bool) error) *MockUpdater_UpdatePersistentConfig_Call { - _c.Call.Return(run) - return _c -} - -// NewMockUpdater creates a new instance of MockUpdater. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewMockUpdater(t interface { - mock.TestingT - Cleanup(func()) -}) *MockUpdater { - mock := &MockUpdater{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/pkg/lib/gateway/gateway.go b/pkg/lib/gateway/gateway.go index fa961aecb..5bc634534 100644 --- a/pkg/lib/gateway/gateway.go +++ b/pkg/lib/gateway/gateway.go @@ -51,7 +51,7 @@ type Gateway interface { type gateway struct { fileService files.Service fileObjectService fileobject.Service - cfg config.ConfigModifiable + cfg config.Service server *http.Server listener net.Listener handler *http.ServeMux @@ -67,10 +67,7 @@ func (g *gateway) gatewayListener() (net.Listener, error) { return net.Listen("tcp", addr) } - var addr string - g.cfg.Read(func(c *config.ConfigPersistent) { - addr = c.GatewayAddr - }) + addr := g.cfg.GetPersistentConfig().GatewayAddr listener, err := netutil.GetTcpListener(addr) if err != nil { // it means we are not able to run on both preferred and random port @@ -92,7 +89,7 @@ func (g *gateway) gatewayListener() (net.Listener, error) { func (g *gateway) Init(a *app.App) (err error) { g.fileService = app.MustComponent[files.Service](a) g.fileObjectService = app.MustComponent[fileobject.Service](a) - g.cfg = a.MustComponent(config.CName).(config.ConfigModifiable) + g.cfg = a.MustComponent(config.CName).(config.Service) return nil } diff --git a/pkg/lib/gateway/gateway_test.go b/pkg/lib/gateway/gateway_test.go index 5b0201d97..c91f9097d 100644 --- a/pkg/lib/gateway/gateway_test.go +++ b/pkg/lib/gateway/gateway_test.go @@ -97,12 +97,15 @@ func newFixture(t *testing.T) *fixture { fileService := mock_files.NewMockService(t) fileObjectService := mock_fileobject.NewMockService(t) + cfg := mock_config.NewMockService(t) gw := New().(*gateway) - ctx := context.Background() + a.Register(testutil.PrepareMock(ctx, a, cfg)) a.Register(testutil.PrepareMock(ctx, a, fileService)) a.Register(testutil.PrepareMock(ctx, a, fileObjectService)) a.Register(gw) + cfg.EXPECT().GetPersistentConfig().Return(config.ConfigPersistent{GatewayAddr: "127.0.0.1:0"}) + err := a.Start(ctx) assert.NoError(t, err) @@ -175,7 +178,7 @@ func TestRetryReader(t *testing.T) { } func TestDoubleStart(t *testing.T) { - cfg := mock_config.NewMockUpdater(t) + cfg := mock_config.NewMockService(t) cfg.EXPECT().UpdatePersistentConfig(mock.Anything).Return(nil).Run(func(f func(cfgp *config.ConfigPersistent) bool) { cfgp := &config.ConfigPersistent{ GatewayAddr: "127.0.0.1:0", @@ -191,7 +194,7 @@ func TestDoubleStart(t *testing.T) { } func TestStartStopStart(t *testing.T) { - cfg := mock_config.NewMockUpdater(t) + cfg := mock_config.NewMockService(t) cfg.EXPECT().UpdatePersistentConfig(mock.Anything).Return(nil).Run(func(f func(cfgp *config.ConfigPersistent) bool) { cfgp := &config.ConfigPersistent{ GatewayAddr: "127.0.0.1:0",