Compare commits

..

2 commits

Author SHA1 Message Date
6f06adc37d ♻️ Refactor config
Make it easier to setup stores
2025-01-26 20:07:45 -06:00
ecae0d5f83 🤡 Use uber mock for mocks 2025-01-24 16:27:05 -06:00
21 changed files with 2910 additions and 206 deletions

View file

@ -15,6 +15,13 @@ tasks:
- go fmt ./...
- go mod tidy
gen:
desc: Generate files
sources:
- '**/*.go'
cmds:
- go generate ./...
vet:
desc: Vet go code
sources:

10
app.go
View file

@ -27,7 +27,7 @@ type App struct {
}
func NewApp(ver string, conf config.Config, db store.Store) (*App, error) {
if conf.BaseURL == "" {
if conf.BaseURL() == "" {
return nil, errors.New("missing BaseURL")
}
app := App{
@ -35,7 +35,7 @@ func NewApp(ver string, conf config.Config, db store.Store) (*App, error) {
conf: conf,
}
selfIRI := boxap.DefaultServiceIRI(conf.BaseURL)
selfIRI := boxap.DefaultServiceIRI(conf.BaseURL())
self := boxap.Self(selfIRI)
self.Name = vocab.DefaultNaturalLanguageValue(app.Name())
self.AttributedTo = vocab.IRI(config.DevUrl)
@ -54,7 +54,7 @@ func (l *App) Config() config.Config {
}
func (l *App) Environment() config.Env {
return l.conf.Environment()
return l.conf.Env()
}
func (l *App) Storage() store.Store {
@ -78,10 +78,10 @@ func (l *App) Version() string {
}
func (l *App) Name() string {
if l.conf.Name == "" {
if l.conf.Name() == "" {
return "Lenore"
}
return l.conf.Name
return l.conf.Name()
}
func (l *App) String() string {

View file

@ -4,26 +4,36 @@ import (
"fmt"
"testing"
"codeberg.org/danjones000/combluotion/config"
"codeberg.org/danjones000/combluotion/internal/testmocks"
vocab "github.com/go-ap/activitypub"
"github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
"codeberg.org/danjones000/combluotion/config"
confMock "codeberg.org/danjones000/combluotion/internal/testmocks/config"
storeMock "codeberg.org/danjones000/combluotion/internal/testmocks/store"
)
func TestEmptyBaseURL(t *testing.T) {
c := config.Config{}
a, er := NewApp("0.0.0", c, testmocks.GetStore())
assert.Nil(t, a)
assert.EqualError(t, er, "missing BaseURL")
type appTest struct {
ctrl *gomock.Controller
store *storeMock.MockStore
conf *confMock.MockConfig
}
func TestDefaultEnvironment(t *testing.T) {
c := config.Config{BaseURL: "http://localhost:1234/"}
a, er := NewApp("0.0.0", c, testmocks.GetStore())
assert.NoError(t, er)
if assert.NotNil(t, a) {
assert.Equal(t, config.Dev, a.Environment())
}
func setupAppTest(t *testing.T) appTest {
t.Helper()
ctrl := gomock.NewController(t)
return appTest{ctrl, storeMock.NewMockStore(ctrl), confMock.NewMockConfig(ctrl)}
}
func TestEmptyBaseURL(t *testing.T) {
th := setupAppTest(t)
th.conf.
EXPECT().
BaseURL().
Return("")
a, er := NewApp("0.0.0", th.conf, th.store)
assert.Nil(t, a)
assert.EqualError(t, er, "missing BaseURL")
}
func TestGivenEnvironment(t *testing.T) {
@ -34,17 +44,21 @@ func TestGivenEnvironment(t *testing.T) {
{config.Dev, config.Dev},
{config.Prod, config.Prod},
{config.Qa, config.Qa},
{config.Env("foo"), config.Dev},
{config.Env("✨"), config.Dev},
}
for _, c := range cases {
t.Run(string(c.given), func(t *testing.T) {
conf := config.Config{BaseURL: "http://localhost:1234/", Env: c.given}
a, er := NewApp("0.0.0", conf, testmocks.GetStore())
th := setupAppTest(t)
th.conf.EXPECT().BaseURL().Return("http://localhost:1234/").Times(2)
th.conf.EXPECT().Name().Return("")
th.conf.
EXPECT().
Env().
Return(c.given)
a, er := NewApp("0.0.0", th.conf, th.store)
assert.NoError(t, er)
if assert.NotNil(t, a) {
assert.Equal(t, conf, a.Config())
assert.Equal(t, th.conf, a.Config())
assert.Equal(t, c.exp, a.Environment())
}
})
@ -52,9 +66,11 @@ func TestGivenEnvironment(t *testing.T) {
}
func TestService(t *testing.T) {
th := setupAppTest(t)
base := "http://localhost:1234/"
conf := config.Config{BaseURL: base}
a, er := NewApp("0.0.0.0", conf, testmocks.GetStore())
th.conf.EXPECT().BaseURL().Return(base).Times(2)
th.conf.EXPECT().Name().Return("")
a, er := NewApp("0.0.0.0", th.conf, th.store)
assert.NoError(t, er)
if assert.NotNil(t, a) {
assert.Equal(t, vocab.IRI(base), a.ServiceIRI())
@ -75,9 +91,11 @@ func TestStrings(t *testing.T) {
for _, c := range cases {
t.Run(c.given, func(t *testing.T) {
conf := config.Config{BaseURL: "http://localhost:1234/", Name: c.given}
th := setupAppTest(t)
th.conf.EXPECT().BaseURL().Return("http://localhost:1234/").AnyTimes()
th.conf.EXPECT().Name().Return(c.given).MinTimes(1)
expStr := fmt.Sprintf("%s (%s)", c.exp, "0.0.0.0")
a, er := NewApp("0.0.0.0", conf, testmocks.GetStore())
a, er := NewApp("0.0.0.0", th.conf, th.store)
assert.NoError(t, er)
if assert.NotNil(t, a) {
assert.Equal(t, c.exp, a.Name())

View file

@ -18,7 +18,7 @@ func main() {
quitErr(err)
fmt.Printf("%+v\n", conf)
db, err := store.MakeStore(conf.Conn.Store, conf)
db, err := store.MakeStore(conf.StoreName(), conf)
quitErr(err)
app, err := combluotion.NewApp(config.Version, conf, db)
@ -50,7 +50,9 @@ func getTomlFile() string {
var confStr = `
base_url = "http://localhost:4523/"
[conn]
[stores]
store = "sqlite"
dsn = "store"
[stores.settings.sqlite]
path = "storage"
`

View file

@ -1,18 +1,76 @@
package config
type Config struct {
Name string `toml:"name"`
Env Env `toml:"env"`
BaseURL string `toml:"base_url"`
Conn ConnSettings `toml:"conn"`
import (
"errors"
"github.com/BurntSushi/toml"
)
type config struct {
name string
env Env
baseURL string
stores stores
md toml.MetaData
}
type ConnSettings struct {
Store string `toml:"store"`
DSN string `toml:"dsn"`
Settings map[string]any `toml:"settings"`
var _ Config = config{}
func (c config) Name() string {
return c.name
}
func (c Config) Environment() Env {
return ValidEnvOrDev(c.Env)
func (c config) Env() Env {
return ValidEnvOrDev(c.env)
}
func (c config) BaseURL() string {
return c.baseURL
}
func (c config) Store(name string) (Store, error) {
if name == "" {
name = c.stores.store
}
return c.stores.GetStore(name)
}
func (c config) StoreName() string {
return c.stores.store
}
type stores struct {
store string
settings map[string]toml.Primitive
conf *config
}
var ErrMissingStore = errors.New("unknown store")
func (ss stores) GetStore(name string) (Store, error) {
if tp, ok := ss.settings[name]; ok {
return store{name, tp, ss.conf.md}, nil
}
return nil, ErrMissingStore
}
type store struct {
name string
settings toml.Primitive
md toml.MetaData
}
var _ Store = store{}
func (s store) Name() string {
return s.name
}
func (s store) Map() (m map[string]any, err error) {
err = s.Decode(&m)
return
}
func (s store) Decode(v any) error {
return s.md.PrimitiveDecode(s.settings, v)
}

View file

@ -7,20 +7,20 @@ import (
)
func TestEnvDefaultsToDev(t *testing.T) {
c := Config{}
assert.Equal(t, Dev, c.Environment())
c := config{}
assert.Equal(t, Dev, c.Env())
}
func TestInvalidEnvReturnsDev(t *testing.T) {
c := Config{Env: Env("foobar")}
assert.Equal(t, Dev, c.Environment())
c := config{env: Env("foobar")}
assert.Equal(t, Dev, c.Env())
}
func TestValidEnvReturnsCorrect(t *testing.T) {
for _, e := range Envs {
t.Run(string(e), func(t *testing.T) {
c := Config{Env: e}
assert.Equal(t, e, c.Environment())
c := config{env: e}
assert.Equal(t, e, c.Env())
})
}
}

17
config/interface.go Normal file
View file

@ -0,0 +1,17 @@
package config
//go:generate mockgen -source interface.go -destination ../internal/testmocks/config/config_mock.go -package config -typed
type Config interface {
Name() string
Env() Env
BaseURL() string
StoreName() string
Store(name string) (Store, error)
}
type Store interface {
Name() string
Decode(v any) error
Map() (map[string]any, error)
}

View file

@ -2,7 +2,39 @@ package config
import "github.com/BurntSushi/toml"
func LoadFromToml(path string) (c Config, err error) {
_, err = toml.DecodeFile(path, &c)
return
type confToml struct {
Name string
Env Env
BaseURL string `toml:"base_url"`
Stores storeSettings `toml:"stores"`
}
type storeSettings struct {
Store string
Settings map[string]toml.Primitive
}
func LoadFromToml(path string) (Config, error) {
var c confToml
md, err := toml.DecodeFile(path, &c)
if err != nil {
return nil, err
}
conf := config{
name: c.Name,
env: c.Env,
baseURL: c.BaseURL,
md: md,
}
st := stores{
store: c.Stores.Store,
settings: c.Stores.Settings,
conf: &conf,
}
conf.stores = st
return conf, nil
}

View file

@ -13,18 +13,33 @@ func TestLoadTomlMissing(t *testing.T) {
assert.Error(t, e)
}
type sqlSett struct {
Path string
Num int
}
func TestLoadTomlGood(t *testing.T) {
tmp, _ := os.CreateTemp("", "*.toml")
defer os.Remove(tmp.Name())
defer tmp.Close()
fmt.Fprintln(tmp, `name = "Cool"`)
fmt.Fprintln(tmp, "[conn]")
fmt.Fprintln(tmp, "[stores]")
fmt.Fprintln(tmp, `store = "sqlite"`)
fmt.Fprintln(tmp, "[conn.settings]")
fmt.Fprintln(tmp, "[stores.settings.sqlite]")
fmt.Fprintln(tmp, `path = "tmp"`)
fmt.Fprintln(tmp, `num = 42`)
c, e := LoadFromToml(tmp.Name())
assert.NoError(t, e)
assert.Equal(t, "Cool", c.Name)
assert.Equal(t, "sqlite", c.Conn.Store)
assert.Equal(t, int64(42), c.Conn.Settings["num"])
assert.Equal(t, "Cool", c.Name())
st, err := c.Store("")
assert.NoError(t, err)
assert.Equal(t, "sqlite", st.Name())
var sett sqlSett
err = st.Decode(&sett)
assert.NoError(t, err)
assert.Equal(t, 42, sett.Num)
assert.Equal(t, "tmp", sett.Path)
}

1
go.mod
View file

@ -12,6 +12,7 @@ require (
github.com/go-ap/storage-sqlite v0.0.0-20240910151457-20fa80d963aa
github.com/openshift/osin v1.0.2-0.20220317075346-0f4d38c6e53f
github.com/stretchr/testify v1.9.0
go.uber.org/mock v0.5.0
)
require (

2
go.sum
View file

@ -83,6 +83,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=

View file

@ -0,0 +1,371 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: interface.go
//
// Generated by this command:
//
// mockgen -source interface.go -destination ../internal/testmocks/config/config_mock.go -package config -typed
//
// Package config is a generated GoMock package.
package config
import (
reflect "reflect"
config "codeberg.org/danjones000/combluotion/config"
gomock "go.uber.org/mock/gomock"
)
// MockConfig is a mock of Config interface.
type MockConfig struct {
ctrl *gomock.Controller
recorder *MockConfigMockRecorder
isgomock struct{}
}
// MockConfigMockRecorder is the mock recorder for MockConfig.
type MockConfigMockRecorder struct {
mock *MockConfig
}
// NewMockConfig creates a new mock instance.
func NewMockConfig(ctrl *gomock.Controller) *MockConfig {
mock := &MockConfig{ctrl: ctrl}
mock.recorder = &MockConfigMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockConfig) EXPECT() *MockConfigMockRecorder {
return m.recorder
}
// BaseURL mocks base method.
func (m *MockConfig) BaseURL() string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "BaseURL")
ret0, _ := ret[0].(string)
return ret0
}
// BaseURL indicates an expected call of BaseURL.
func (mr *MockConfigMockRecorder) BaseURL() *MockConfigBaseURLCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BaseURL", reflect.TypeOf((*MockConfig)(nil).BaseURL))
return &MockConfigBaseURLCall{Call: call}
}
// MockConfigBaseURLCall wrap *gomock.Call
type MockConfigBaseURLCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockConfigBaseURLCall) Return(arg0 string) *MockConfigBaseURLCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockConfigBaseURLCall) Do(f func() string) *MockConfigBaseURLCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockConfigBaseURLCall) DoAndReturn(f func() string) *MockConfigBaseURLCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// Env mocks base method.
func (m *MockConfig) Env() config.Env {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Env")
ret0, _ := ret[0].(config.Env)
return ret0
}
// Env indicates an expected call of Env.
func (mr *MockConfigMockRecorder) Env() *MockConfigEnvCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Env", reflect.TypeOf((*MockConfig)(nil).Env))
return &MockConfigEnvCall{Call: call}
}
// MockConfigEnvCall wrap *gomock.Call
type MockConfigEnvCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockConfigEnvCall) Return(arg0 config.Env) *MockConfigEnvCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockConfigEnvCall) Do(f func() config.Env) *MockConfigEnvCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockConfigEnvCall) DoAndReturn(f func() config.Env) *MockConfigEnvCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// Name mocks base method.
func (m *MockConfig) Name() string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Name")
ret0, _ := ret[0].(string)
return ret0
}
// Name indicates an expected call of Name.
func (mr *MockConfigMockRecorder) Name() *MockConfigNameCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockConfig)(nil).Name))
return &MockConfigNameCall{Call: call}
}
// MockConfigNameCall wrap *gomock.Call
type MockConfigNameCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockConfigNameCall) Return(arg0 string) *MockConfigNameCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockConfigNameCall) Do(f func() string) *MockConfigNameCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockConfigNameCall) DoAndReturn(f func() string) *MockConfigNameCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// Store mocks base method.
func (m *MockConfig) Store(name string) (config.Store, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Store", name)
ret0, _ := ret[0].(config.Store)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Store indicates an expected call of Store.
func (mr *MockConfigMockRecorder) Store(name any) *MockConfigStoreCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Store", reflect.TypeOf((*MockConfig)(nil).Store), name)
return &MockConfigStoreCall{Call: call}
}
// MockConfigStoreCall wrap *gomock.Call
type MockConfigStoreCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockConfigStoreCall) Return(arg0 config.Store, arg1 error) *MockConfigStoreCall {
c.Call = c.Call.Return(arg0, arg1)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockConfigStoreCall) Do(f func(string) (config.Store, error)) *MockConfigStoreCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockConfigStoreCall) DoAndReturn(f func(string) (config.Store, error)) *MockConfigStoreCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// StoreName mocks base method.
func (m *MockConfig) StoreName() string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "StoreName")
ret0, _ := ret[0].(string)
return ret0
}
// StoreName indicates an expected call of StoreName.
func (mr *MockConfigMockRecorder) StoreName() *MockConfigStoreNameCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StoreName", reflect.TypeOf((*MockConfig)(nil).StoreName))
return &MockConfigStoreNameCall{Call: call}
}
// MockConfigStoreNameCall wrap *gomock.Call
type MockConfigStoreNameCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockConfigStoreNameCall) Return(arg0 string) *MockConfigStoreNameCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockConfigStoreNameCall) Do(f func() string) *MockConfigStoreNameCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockConfigStoreNameCall) DoAndReturn(f func() string) *MockConfigStoreNameCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// MockStore is a mock of Store interface.
type MockStore struct {
ctrl *gomock.Controller
recorder *MockStoreMockRecorder
isgomock struct{}
}
// MockStoreMockRecorder is the mock recorder for MockStore.
type MockStoreMockRecorder struct {
mock *MockStore
}
// NewMockStore creates a new mock instance.
func NewMockStore(ctrl *gomock.Controller) *MockStore {
mock := &MockStore{ctrl: ctrl}
mock.recorder = &MockStoreMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockStore) EXPECT() *MockStoreMockRecorder {
return m.recorder
}
// Decode mocks base method.
func (m *MockStore) Decode(v any) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Decode", v)
ret0, _ := ret[0].(error)
return ret0
}
// Decode indicates an expected call of Decode.
func (mr *MockStoreMockRecorder) Decode(v any) *MockStoreDecodeCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Decode", reflect.TypeOf((*MockStore)(nil).Decode), v)
return &MockStoreDecodeCall{Call: call}
}
// MockStoreDecodeCall wrap *gomock.Call
type MockStoreDecodeCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockStoreDecodeCall) Return(arg0 error) *MockStoreDecodeCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockStoreDecodeCall) Do(f func(any) error) *MockStoreDecodeCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockStoreDecodeCall) DoAndReturn(f func(any) error) *MockStoreDecodeCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// Map mocks base method.
func (m *MockStore) Map() (map[string]any, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Map")
ret0, _ := ret[0].(map[string]any)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Map indicates an expected call of Map.
func (mr *MockStoreMockRecorder) Map() *MockStoreMapCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Map", reflect.TypeOf((*MockStore)(nil).Map))
return &MockStoreMapCall{Call: call}
}
// MockStoreMapCall wrap *gomock.Call
type MockStoreMapCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockStoreMapCall) Return(arg0 map[string]any, arg1 error) *MockStoreMapCall {
c.Call = c.Call.Return(arg0, arg1)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockStoreMapCall) Do(f func() (map[string]any, error)) *MockStoreMapCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockStoreMapCall) DoAndReturn(f func() (map[string]any, error)) *MockStoreMapCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// Name mocks base method.
func (m *MockStore) Name() string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Name")
ret0, _ := ret[0].(string)
return ret0
}
// Name indicates an expected call of Name.
func (mr *MockStoreMockRecorder) Name() *MockStoreNameCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockStore)(nil).Name))
return &MockStoreNameCall{Call: call}
}
// MockStoreNameCall wrap *gomock.Call
type MockStoreNameCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockStoreNameCall) Return(arg0 string) *MockStoreNameCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockStoreNameCall) Do(f func() string) *MockStoreNameCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockStoreNameCall) DoAndReturn(f func() string) *MockStoreNameCall {
c.Call = c.Call.DoAndReturn(f)
return c
}

View file

@ -1,45 +0,0 @@
package testmocks
import (
"codeberg.org/danjones000/combluotion/config"
vocab "github.com/go-ap/activitypub"
"github.com/go-ap/filters"
)
type st struct{}
func (s *st) Bootstrap(config.Config) error {
return nil
}
func (s *st) Load(iri vocab.IRI, filters ...filters.Check) (vocab.Item, error) {
i := vocab.ActorNew(iri, vocab.ActorType)
return i, nil
}
func (s *st) Save(v vocab.Item) (vocab.Item, error) {
return v, nil
}
func (s *st) Delete(v vocab.Item) error {
return nil
}
func (s *st) Create(col vocab.CollectionInterface) (vocab.CollectionInterface, error) {
return col, nil
}
func (s *st) AddTo(col vocab.IRI, it vocab.Item) error {
return nil
}
func (s *st) RemoveFrom(col vocab.IRI, it vocab.Item) error {
return nil
}
func (s *st) Close() {
}
func GetStore() *st {
return &st{}
}

File diff suppressed because it is too large Load diff

View file

@ -1,20 +0,0 @@
package testmocks
import (
"crypto"
vocab "github.com/go-ap/activitypub"
proc "github.com/go-ap/processing"
)
func (s *st) LoadKey(vocab.IRI) (crypto.PrivateKey, error) {
return nil, nil
}
func (s *st) LoadMetadata(vocab.IRI) (*proc.Metadata, error) {
return nil, nil
}
func (s *st) SaveMetadata(proc.Metadata, vocab.IRI) error {
return nil
}

View file

@ -1,37 +0,0 @@
package testmocks
import (
"github.com/openshift/osin"
)
func (s *st) LoadAccess(string) (*osin.AccessData, error) {
return nil, nil
}
func (s *st) SaveAccess(*osin.AccessData) error {
return nil
}
func (s *st) RemoveAccess(string) error {
return nil
}
func (s *st) LoadAuthorize(string) (*osin.AuthorizeData, error) {
return nil, nil
}
func (s *st) SaveAuthorize(*osin.AuthorizeData) error {
return nil
}
func (s *st) RemoveAuthorize(string) error {
return nil
}
func (s *st) LoadRefresh(string) (*osin.AccessData, error) {
return nil, nil
}
func (s *st) RemoveRefresh(string) error {
return nil
}

View file

@ -1,30 +0,0 @@
package testmocks
import (
"github.com/openshift/osin"
)
func (s *st) Clone() osin.Storage {
n := *s
return &n
}
func (s *st) GetClient(string) (osin.Client, error) {
return &osin.DefaultClient{}, nil
}
func (s *st) CreateClient(osin.Client) error {
return nil
}
func (s *st) UpdateClient(osin.Client) error {
return nil
}
func (s *st) RemoveClient(string) error {
return nil
}
func (s *st) ListClients() (cl []osin.Client, er error) {
return
}

View file

@ -9,7 +9,7 @@ import (
var ErrNoFactory = errors.New("unknown factory")
type StoreFactory func(config.Config) (Store, error)
type StoreFactory func(config.Store) (Store, error)
var factories map[string]StoreFactory
@ -26,13 +26,18 @@ func GetFactory(name string) StoreFactory {
}
func MakeStore(name string, conf config.Config) (Store, error) {
st, err := conf.Store(name)
if err != nil {
return nil, err
}
if name == "" {
name = conf.Conn.Store
name = st.Name()
}
f, ok := factories[name]
if !ok {
return nil, fmt.Errorf("%w: %s", ErrNoFactory, name)
}
return f(conf)
return f(st)
}

View file

@ -3,17 +3,35 @@ package store
import (
"testing"
"codeberg.org/danjones000/combluotion/config"
"codeberg.org/danjones000/combluotion/internal/testmocks"
"github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
"codeberg.org/danjones000/combluotion/config"
confMock "codeberg.org/danjones000/combluotion/internal/testmocks/config"
storeMock "codeberg.org/danjones000/combluotion/internal/testmocks/store"
)
var f StoreFactory = func(config.Config) (Store, error) {
return testmocks.GetStore(), nil
type testHelp struct {
ctrl *gomock.Controller
store *storeMock.MockStore
fact StoreFactory
conf *confMock.MockConfig
}
func setupFactoryTest(t *testing.T) testHelp {
t.Helper()
ctrl := gomock.NewController(t)
store := storeMock.NewMockStore(ctrl)
fact := func(config.Store) (Store, error) {
return store, nil
}
return testHelp{ctrl, store, fact, confMock.NewMockConfig(ctrl)}
}
func TestAddFactory(t *testing.T) {
AddFactory("mock", f)
th := setupFactoryTest(t)
AddFactory("mock", th.fact)
defer delete(factories, "mock")
_, ok := factories["mock"]
assert.True(t, ok)
@ -25,33 +43,52 @@ func TestGetFactoryNil(t *testing.T) {
}
func TestGetFactoryNotNil(t *testing.T) {
AddFactory("mock", f)
th := setupFactoryTest(t)
AddFactory("mock", th.fact)
defer delete(factories, "mock")
f := GetFactory("mock")
assert.NotNil(t, f)
}
func TestMakeStoreError(t *testing.T) {
s, e := MakeStore("mock", config.Config{})
th := setupFactoryTest(t)
th.conf.
EXPECT().
Store("mock").
Return(nil, nil)
s, e := MakeStore("mock", th.conf)
assert.Nil(t, s)
assert.ErrorIs(t, e, ErrNoFactory)
assert.ErrorContains(t, e, ErrNoFactory.Error()+": mock")
}
func TestMakeStoreNoError(t *testing.T) {
AddFactory("mock", f)
th := setupFactoryTest(t)
th.conf.
EXPECT().
Store("mock").
Return(nil, nil)
AddFactory("mock", th.fact)
defer delete(factories, "mock")
s, e := MakeStore("mock", config.Config{})
s, e := MakeStore("mock", th.conf)
assert.NotNil(t, s)
assert.NoError(t, e)
}
func TestMakeStoreNoName(t *testing.T) {
AddFactory("mock", f)
th := setupFactoryTest(t)
confStore := confMock.NewMockStore(th.ctrl)
th.conf.
EXPECT().
Store("").
Return(confStore, nil)
confStore.
EXPECT().
Name().
Return("mock")
AddFactory("mock", th.fact)
defer delete(factories, "mock")
s, e := MakeStore("", config.Config{
Conn: config.ConnSettings{Store: "mock"},
})
s, e := MakeStore("", th.conf)
assert.NotNil(t, s)
assert.NoError(t, e)
}

View file

@ -10,8 +10,17 @@ func init() {
store.AddFactory("sqlite", MakeStore)
}
func MakeStore(conf config.Config) (store.Store, error) {
sqlConf := sqlite.Config{Path: conf.Conn.DSN}
type settings struct {
Path string
}
func MakeStore(conf config.Store) (store.Store, error) {
var s settings
err := conf.Decode(&s)
if err != nil {
return nil, err
}
sqlConf := sqlite.Config{Path: s.Path}
db, err := sqlite.New(sqlConf)
if err != nil {
return nil, err

View file

@ -7,6 +7,8 @@ import (
"github.com/openshift/osin"
)
//go:generate mockgen -source store.go -destination ../internal/testmocks/store/store_mock.go -package store -typed
type ClientSaver interface {
// UpdateClient updates the client (identified by it's id) and replaces the values with the values of client.
UpdateClient(c osin.Client) error