Compare commits
22 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fe860fbc82 | |||
| 917f919401 | |||
| d7de194a90 | |||
| 6f06adc37d | |||
| ecae0d5f83 | |||
| c73dfc0d3a | |||
| 8a069859ea | |||
| c703a26c10 | |||
| 25ed67b2e9 | |||
| b8fc873850 | |||
| 9ddaa98ff4 | |||
| e7b88bcc09 | |||
| c4513aa94b | |||
| d6546e5ff9 | |||
| 931f75500f | |||
| 0fe6f5070e | |||
| bdc625b57e | |||
| 0e2d302804 | |||
| 33f140595c | |||
| 6498f3d56b | |||
| e441e541c7 | |||
| 2b888f203d |
27 changed files with 3901 additions and 7 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
.task/
|
||||
95
Taskfile.yml
Normal file
95
Taskfile.yml
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
version: '3'
|
||||
|
||||
tasks:
|
||||
default:
|
||||
cmds:
|
||||
- task: fmt
|
||||
- task: test
|
||||
- task: build
|
||||
|
||||
fmt:
|
||||
desc: Format go code
|
||||
sources:
|
||||
- '**/*.go'
|
||||
cmds:
|
||||
- go fmt ./...
|
||||
- go mod tidy
|
||||
|
||||
gen:
|
||||
desc: Generate files
|
||||
sources:
|
||||
- '**/*.go'
|
||||
cmds:
|
||||
- go generate ./...
|
||||
|
||||
vet:
|
||||
desc: Vet go code
|
||||
sources:
|
||||
- '**/*.go'
|
||||
cmds:
|
||||
- go vet ./...
|
||||
|
||||
critic:
|
||||
desc: Critique go code
|
||||
sources:
|
||||
- '**/*.go'
|
||||
cmds:
|
||||
- gocritic check ./...
|
||||
|
||||
staticcheck:
|
||||
desc: Static check go code
|
||||
sources:
|
||||
- '**/*.go'
|
||||
cmds:
|
||||
- staticcheck ./...
|
||||
|
||||
vuln:
|
||||
desc: Check for vulnerabilities
|
||||
sources:
|
||||
- '**/*.go'
|
||||
cmds:
|
||||
- govulncheck ./...
|
||||
|
||||
lint:
|
||||
desc: Do static analysis
|
||||
deps:
|
||||
- vet
|
||||
- critic
|
||||
- staticcheck
|
||||
- vuln
|
||||
|
||||
test:
|
||||
desc: Run unit tests
|
||||
deps: [fmt, vet]
|
||||
sources:
|
||||
- '**/*.go'
|
||||
generates:
|
||||
- build/cover.out
|
||||
cmds:
|
||||
- go test -race -cover -coverprofile build/cover.out ./...
|
||||
|
||||
coverage-report:
|
||||
desc: Build coverage report
|
||||
deps: [test]
|
||||
sources:
|
||||
- build/cover.out
|
||||
generates:
|
||||
- build/cover.html
|
||||
cmds:
|
||||
- go tool cover -html=build/cover.out -o build/cover.html
|
||||
|
||||
serve-report:
|
||||
desc: Serve the coverage report
|
||||
deps: [coverage-report]
|
||||
cmds:
|
||||
- ip addr list | grep inet
|
||||
- php -S 0.0.0.0:3265 -t build
|
||||
|
||||
build:
|
||||
desc: Build server binary
|
||||
sources:
|
||||
- '**/*.go'
|
||||
generates:
|
||||
- build/combluotion
|
||||
cmds:
|
||||
- go build -o build/combluotion cmd/combluotion/main.go
|
||||
90
app.go
Normal file
90
app.go
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
package combluotion
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"codeberg.org/danjones000/combluotion/config"
|
||||
_ "codeberg.org/danjones000/combluotion/imports"
|
||||
"codeberg.org/danjones000/combluotion/store"
|
||||
vocab "github.com/go-ap/activitypub"
|
||||
"github.com/go-ap/client"
|
||||
boxap "github.com/go-ap/fedbox/activitypub"
|
||||
)
|
||||
|
||||
func init() {
|
||||
client.UserAgent = config.UserAgent
|
||||
}
|
||||
|
||||
type App struct {
|
||||
conf config.Config
|
||||
self vocab.Service
|
||||
user vocab.Person
|
||||
version string
|
||||
storage store.Store
|
||||
client client.C
|
||||
}
|
||||
|
||||
func NewApp(ver string, conf config.Config, db store.Store) (*App, error) {
|
||||
if conf.BaseURL() == "" {
|
||||
return nil, errors.New("missing BaseURL")
|
||||
}
|
||||
app := App{
|
||||
version: ver,
|
||||
conf: conf,
|
||||
storage: db,
|
||||
}
|
||||
|
||||
selfIRI := boxap.DefaultServiceIRI(conf.BaseURL())
|
||||
self := boxap.Self(selfIRI)
|
||||
self.Name = vocab.DefaultNaturalLanguageValue(app.Name())
|
||||
self.AttributedTo = vocab.IRI(config.DevUrl)
|
||||
self.Summary = vocab.DefaultNaturalLanguageValue("ActivityPub-powered reader")
|
||||
self.Published = time.Now()
|
||||
self.Updated = time.Now()
|
||||
|
||||
app.self = self
|
||||
app.client = *client.New()
|
||||
|
||||
return &app, nil
|
||||
}
|
||||
|
||||
func (l *App) Config() config.Config {
|
||||
return l.conf
|
||||
}
|
||||
|
||||
func (l *App) Environment() config.Env {
|
||||
return l.conf.Env()
|
||||
}
|
||||
|
||||
func (l *App) Storage() store.Store {
|
||||
return l.storage
|
||||
}
|
||||
|
||||
func (l *App) Service() vocab.Service {
|
||||
return l.self
|
||||
}
|
||||
|
||||
func (l *App) ServiceIRI() vocab.IRI {
|
||||
return l.self.ID
|
||||
}
|
||||
|
||||
func (l *App) User() vocab.Actor {
|
||||
return l.user
|
||||
}
|
||||
|
||||
func (l *App) Version() string {
|
||||
return l.version
|
||||
}
|
||||
|
||||
func (l *App) Name() string {
|
||||
if l.conf.Name() == "" {
|
||||
return "Lenore"
|
||||
}
|
||||
return l.conf.Name()
|
||||
}
|
||||
|
||||
func (l *App) String() string {
|
||||
return fmt.Sprintf("%s (%s)", l.Name(), l.version)
|
||||
}
|
||||
132
app_test.go
Normal file
132
app_test.go
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
package combluotion
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
type appTest struct {
|
||||
ctrl *gomock.Controller
|
||||
store *storeMock.MockStore
|
||||
conf *confMock.MockConfig
|
||||
}
|
||||
|
||||
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) {
|
||||
cases := [...]struct {
|
||||
given config.Env
|
||||
exp config.Env
|
||||
}{
|
||||
{config.Dev, config.Dev},
|
||||
{config.Prod, config.Prod},
|
||||
{config.Qa, config.Qa},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(string(c.given), func(t *testing.T) {
|
||||
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, th.conf, a.Config())
|
||||
assert.Equal(t, c.exp, a.Environment())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestService(t *testing.T) {
|
||||
th := setupAppTest(t)
|
||||
base := "http://localhost:1234/"
|
||||
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())
|
||||
assert.Equal(t, vocab.IRI(base), a.Service().ID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppStorage(t *testing.T) {
|
||||
th := setupAppTest(t)
|
||||
base := "http://localhost:1234/"
|
||||
th.conf.EXPECT().BaseURL().Return(base).MinTimes(1)
|
||||
th.conf.EXPECT().Name().Return("").AnyTimes()
|
||||
a, er := NewApp("0.0.0.0", th.conf, th.store)
|
||||
assert.NoError(t, er)
|
||||
if assert.NotNil(t, a) {
|
||||
assert.Equal(t, th.store, a.Storage())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppUser(t *testing.T) {
|
||||
// TODO: Actually fill this out at some point
|
||||
th := setupAppTest(t)
|
||||
base := "http://localhost:1234/"
|
||||
th.conf.EXPECT().BaseURL().Return(base).MinTimes(1)
|
||||
th.conf.EXPECT().Name().Return("").AnyTimes()
|
||||
a, er := NewApp("0.0.0.0", th.conf, th.store)
|
||||
assert.NoError(t, er)
|
||||
if assert.NotNil(t, a) {
|
||||
assert.Zero(t, a.User())
|
||||
}
|
||||
}
|
||||
|
||||
func TestStrings(t *testing.T) {
|
||||
cases := [...]struct {
|
||||
given string
|
||||
exp string
|
||||
}{
|
||||
{"", "Lenore"},
|
||||
{"Lenore", "Lenore"},
|
||||
{"Danny Ray", "Danny Ray"},
|
||||
{"✨👹", "✨👹"},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.given, func(t *testing.T) {
|
||||
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", th.conf, th.store)
|
||||
assert.NoError(t, er)
|
||||
if assert.NotNil(t, a) {
|
||||
assert.Equal(t, c.exp, a.Name())
|
||||
assert.Equal(t, "0.0.0.0", a.Version())
|
||||
assert.Equal(t, expStr, a.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
3
build/.gitignore
vendored
3
build/.gitignore
vendored
|
|
@ -1 +1,2 @@
|
|||
lenore
|
||||
*
|
||||
!.gitignore
|
||||
|
|
|
|||
59
cmd/combluotion/main.go
Normal file
59
cmd/combluotion/main.go
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
package main
|
||||
|
||||
// @todo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"codeberg.org/danjones000/combluotion"
|
||||
"codeberg.org/danjones000/combluotion/config"
|
||||
"codeberg.org/danjones000/combluotion/store"
|
||||
)
|
||||
|
||||
func main() {
|
||||
f := getTomlFile()
|
||||
defer os.Remove(f)
|
||||
conf, err := config.LoadFromToml(f)
|
||||
quitErr(err)
|
||||
fmt.Printf("%+v\n", conf)
|
||||
|
||||
db, err := store.MakeStore(conf.StoreName(), conf)
|
||||
quitErr(err)
|
||||
|
||||
app, err := combluotion.NewApp(config.Version, conf, db)
|
||||
quitErr(err)
|
||||
|
||||
fmt.Println(app)
|
||||
serv := app.Service()
|
||||
out, _ := serv.MarshalJSON()
|
||||
fmt.Println(string(out))
|
||||
fmt.Println(serv.ID)
|
||||
}
|
||||
|
||||
func quitErr(err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func getTomlFile() string {
|
||||
tmp, err := os.CreateTemp("", "*.toml")
|
||||
quitErr(err)
|
||||
defer tmp.Close()
|
||||
|
||||
p := tmp.Name()
|
||||
fmt.Fprintln(tmp, confStr)
|
||||
return p
|
||||
}
|
||||
|
||||
var confStr = `
|
||||
base_url = "http://localhost:4523/"
|
||||
env = "dev"
|
||||
|
||||
[stores]
|
||||
store = "sqlite"
|
||||
|
||||
[stores.settings.sqlite]
|
||||
path = "storage"
|
||||
`
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
package main
|
||||
|
||||
func main() {
|
||||
|
||||
}
|
||||
76
config/config.go
Normal file
76
config/config.go
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
name string
|
||||
env Env
|
||||
baseURL string
|
||||
stores stores
|
||||
md toml.MetaData
|
||||
}
|
||||
|
||||
var _ Config = config{}
|
||||
|
||||
func (c config) Name() string {
|
||||
return c.name
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
64
config/config_test.go
Normal file
64
config/config_test.go
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestEnvDefaultsToDev(t *testing.T) {
|
||||
c := config{}
|
||||
assert.Equal(t, Dev, c.Env())
|
||||
}
|
||||
|
||||
func TestInvalidEnvReturnsDev(t *testing.T) {
|
||||
c := config{env: Env(255)}
|
||||
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.Env())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigBaseURL(t *testing.T) {
|
||||
c := config{baseURL: "https://me.goodevilgenius.org"}
|
||||
assert.Equal(t, c.baseURL, c.BaseURL())
|
||||
}
|
||||
|
||||
func TestConfigStoreName(t *testing.T) {
|
||||
c := config{stores: stores{store: "cockroachdb"}}
|
||||
assert.Equal(t, c.stores.store, c.StoreName())
|
||||
}
|
||||
|
||||
func TestStoresMissingStore(t *testing.T) {
|
||||
ss := stores{}
|
||||
st, er := ss.GetStore("cockroachdb")
|
||||
assert.Nil(t, st)
|
||||
assert.ErrorIs(t, er, ErrMissingStore)
|
||||
}
|
||||
|
||||
var mockToml = `
|
||||
[cockroachdb]
|
||||
|
||||
dsn = "cockroachdb://user:pass@127.0.0.1:26257/combluotion"
|
||||
`
|
||||
|
||||
type mockConn struct {
|
||||
CockroachDB toml.Primitive
|
||||
}
|
||||
|
||||
func TestStoreMap(t *testing.T) {
|
||||
var conn mockConn
|
||||
md, _ := toml.Decode(mockToml, &conn)
|
||||
st := store{"cockroachdb", conn.CockroachDB, md}
|
||||
|
||||
m, er := st.Map()
|
||||
assert.NoError(t, er)
|
||||
assert.Equal(t, "cockroachdb://user:pass@127.0.0.1:26257/combluotion", m["dsn"])
|
||||
}
|
||||
63
config/env.go
Normal file
63
config/env.go
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//go:generate stringer -type Env
|
||||
|
||||
type Env uint8
|
||||
|
||||
const (
|
||||
Dev Env = iota + 1
|
||||
Prod
|
||||
Qa
|
||||
Test
|
||||
)
|
||||
|
||||
var Envs = [...]Env{
|
||||
Dev,
|
||||
Prod,
|
||||
Qa,
|
||||
Test,
|
||||
}
|
||||
|
||||
func (e Env) MarshalText() ([]byte, error) {
|
||||
return []byte(e.String()), nil
|
||||
}
|
||||
|
||||
var ErrEnvUnmarshal = errors.New("unable to unmarshal value")
|
||||
|
||||
func (e *Env) UnmarshalText(text []byte) error {
|
||||
if e == nil {
|
||||
return fmt.Errorf("%w: nil pointer", ErrEnvUnmarshal)
|
||||
}
|
||||
|
||||
val := strings.ToUpper(string(text))
|
||||
|
||||
for _, ee := range Envs {
|
||||
if val == strings.ToUpper(ee.String()) {
|
||||
*e = ee
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("%w: invalid value: %s", ErrEnvUnmarshal, text)
|
||||
}
|
||||
|
||||
func ValidEnvOrDev(e Env) Env {
|
||||
if ValidEnv(e) {
|
||||
return e
|
||||
}
|
||||
return Dev
|
||||
}
|
||||
|
||||
func ValidEnv(env Env) bool {
|
||||
for _, e := range Envs {
|
||||
if env == e {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
27
config/env_string.go
Normal file
27
config/env_string.go
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// Code generated by "stringer -type Env"; DO NOT EDIT.
|
||||
|
||||
package config
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[Dev-1]
|
||||
_ = x[Prod-2]
|
||||
_ = x[Qa-3]
|
||||
_ = x[Test-4]
|
||||
}
|
||||
|
||||
const _Env_name = "DevProdQaTest"
|
||||
|
||||
var _Env_index = [...]uint8{0, 3, 7, 9, 13}
|
||||
|
||||
func (i Env) String() string {
|
||||
i -= 1
|
||||
if i >= Env(len(_Env_index)-1) {
|
||||
return "Env(" + strconv.FormatInt(int64(i+1), 10) + ")"
|
||||
}
|
||||
return _Env_name[_Env_index[i]:_Env_index[i+1]]
|
||||
}
|
||||
117
config/env_test.go
Normal file
117
config/env_test.go
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var _ encoding.TextMarshaler = Env(0)
|
||||
var _ encoding.TextUnmarshaler = new(Env)
|
||||
var _ fmt.Stringer = Env(0)
|
||||
|
||||
func TestEnvString(t *testing.T) {
|
||||
testcases := []struct {
|
||||
expected string
|
||||
val Env
|
||||
}{
|
||||
{"Dev", Dev},
|
||||
{"Prod", Prod},
|
||||
{"Qa", Qa},
|
||||
{"Test", Test},
|
||||
{"Env(0)", Env(0)},
|
||||
{"Env(255)", Env(255)},
|
||||
}
|
||||
for _, testcase := range testcases {
|
||||
t.Run(testcase.expected, func(sub *testing.T) {
|
||||
assert.Equal(t, testcase.expected, testcase.val.String())
|
||||
by, er := testcase.val.MarshalText()
|
||||
assert.NoError(t, er)
|
||||
assert.Equal(t, []byte(testcase.expected), by)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type unmarshaltest struct {
|
||||
name string
|
||||
in []byte
|
||||
exp Env
|
||||
err string
|
||||
}
|
||||
|
||||
func TestEnvUnmarshalText(t *testing.T) {
|
||||
testcases := []unmarshaltest{
|
||||
{"empty", []byte{}, Env(0), "invalid value: "},
|
||||
{"bad value", []byte("foobar"), Env(0), "invalid value: foobar"},
|
||||
}
|
||||
for _, e := range Envs {
|
||||
testcases = append(testcases, unmarshaltest{e.String() + "-lower", []byte(strings.ToLower(e.String())), e, ""})
|
||||
testcases = append(testcases, unmarshaltest{e.String() + "-upper", []byte(strings.ToUpper(e.String())), e, ""})
|
||||
testcases = append(testcases, unmarshaltest{e.String(), []byte(e.String()), e, ""})
|
||||
}
|
||||
|
||||
for _, testcase := range testcases {
|
||||
t.Run(testcase.name, func(sub *testing.T) {
|
||||
var e Env
|
||||
er := (&e).UnmarshalText(testcase.in)
|
||||
if testcase.err == "" {
|
||||
assert.NoError(t, er)
|
||||
assert.Equal(t, testcase.exp, e)
|
||||
} else {
|
||||
assert.Empty(t, e)
|
||||
assert.ErrorContains(t, er, testcase.err)
|
||||
assert.ErrorIs(t, er, ErrEnvUnmarshal)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvUnmarshalTextNil(t *testing.T) {
|
||||
var e *Env
|
||||
er := e.UnmarshalText([]byte("prod"))
|
||||
assert.ErrorContains(t, er, "nil pointer")
|
||||
assert.ErrorIs(t, er, ErrEnvUnmarshal)
|
||||
}
|
||||
|
||||
func TestValidEnv(t *testing.T) {
|
||||
cases := [...]struct {
|
||||
e Env
|
||||
exp bool
|
||||
}{
|
||||
{Dev, true},
|
||||
{Prod, true},
|
||||
{Qa, true},
|
||||
{Test, true},
|
||||
{Env(0), false},
|
||||
{Env(255), false},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(string(c.e), func(t *testing.T) {
|
||||
assert.Equal(t, c.exp, ValidEnv(c.e))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidEnvOrDev(t *testing.T) {
|
||||
cases := [...]struct {
|
||||
give Env
|
||||
exp Env
|
||||
}{
|
||||
{Dev, Dev},
|
||||
{Prod, Prod},
|
||||
{Qa, Qa},
|
||||
{Test, Test},
|
||||
{Env(0), Dev},
|
||||
{Env(255), Dev},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(string(c.give), func(t *testing.T) {
|
||||
assert.Equal(t, c.exp, ValidEnvOrDev(c.give))
|
||||
})
|
||||
}
|
||||
}
|
||||
17
config/interface.go
Normal file
17
config/interface.go
Normal 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)
|
||||
}
|
||||
40
config/load.go
Normal file
40
config/load.go
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
package config
|
||||
|
||||
import "github.com/BurntSushi/toml"
|
||||
|
||||
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
|
||||
}
|
||||
47
config/load_test.go
Normal file
47
config/load_test.go
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestLoadTomlMissing(t *testing.T) {
|
||||
_, e := LoadFromToml("not-a-real-filee")
|
||||
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, `env = "prod"`)
|
||||
fmt.Fprintln(tmp, "[stores]")
|
||||
fmt.Fprintln(tmp, `store = "sqlite"`)
|
||||
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, Prod, c.Env())
|
||||
|
||||
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)
|
||||
}
|
||||
10
config/version.go
Normal file
10
config/version.go
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
package config
|
||||
|
||||
const (
|
||||
AppName string = "combluotion"
|
||||
Version string = "0.0.1"
|
||||
Url string = "https://codeberg.org/danjones000/combluotion"
|
||||
DevUrl string = "https://codeberg.org/danjones000"
|
||||
Email string = "danjones@goodevilgenius.org"
|
||||
UserAgent string = AppName + "/" + Version + " (" + Url + "; " + Email + ")"
|
||||
)
|
||||
53
go.mod
53
go.mod
|
|
@ -1,3 +1,54 @@
|
|||
module codeberg.org/danjones000/lenore
|
||||
module codeberg.org/danjones000/combluotion
|
||||
|
||||
go 1.23.1
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.4.0
|
||||
github.com/go-ap/activitypub v0.0.0-20240910141749-b4b8c8aa484c
|
||||
github.com/go-ap/client v0.0.0-20240910141951-13a4f3c4fd53
|
||||
github.com/go-ap/fedbox v0.0.0-20240910163620-7bcedb2eb399
|
||||
github.com/go-ap/filters v0.0.0-20240910141936-c8f68cdf2bc9
|
||||
github.com/go-ap/processing v0.0.0-20240910151355-8284a5ce9c22
|
||||
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 (
|
||||
git.sr.ht/~mariusor/cache v0.0.0-20240905174905-d68f888f114e // indirect
|
||||
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 // indirect
|
||||
git.sr.ht/~mariusor/lw v0.0.0-20240906100438-00d2184b2120 // indirect
|
||||
git.sr.ht/~mariusor/ssm v0.0.0-20240811085540-34f24cac52b7 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/go-ap/cache v0.0.0-20240910141827-94f8ac1a9133 // indirect
|
||||
github.com/go-ap/errors v0.0.0-20240910140019-1e9d33cc1568 // indirect
|
||||
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73 // indirect
|
||||
github.com/go-chi/chi/v5 v5.1.0 // indirect
|
||||
github.com/go-fed/httpsig v1.1.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||
github.com/mariusor/qstring v0.0.0-20200204164351-5a99d46de39d // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.23 // indirect
|
||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||
github.com/pborman/uuid v1.2.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/rs/xid v1.6.0 // indirect
|
||||
github.com/rs/zerolog v1.33.0 // indirect
|
||||
github.com/valyala/fastjson v1.6.4 // indirect
|
||||
golang.org/x/crypto v0.27.0 // indirect
|
||||
golang.org/x/oauth2 v0.23.0 // indirect
|
||||
golang.org/x/sys v0.25.0 // indirect
|
||||
golang.org/x/text v0.18.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
modernc.org/gc/v3 v3.0.0-20240801135723-a856999a2e4a // indirect
|
||||
modernc.org/mathutil v1.6.0 // indirect
|
||||
modernc.org/memory v1.8.0 // indirect
|
||||
modernc.org/sqlite v1.33.0 // indirect
|
||||
modernc.org/strutil v1.2.0 // indirect
|
||||
modernc.org/token v1.1.0 // indirect
|
||||
)
|
||||
|
|
|
|||
136
go.sum
Normal file
136
go.sum
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
git.sr.ht/~mariusor/cache v0.0.0-20240905174905-d68f888f114e h1:JmQa0+xdOJFmXmxeBPg5SuFyqA5/4YBwooYCJIefpWk=
|
||||
git.sr.ht/~mariusor/cache v0.0.0-20240905174905-d68f888f114e/go.mod h1:Yv1mSKccec0/7Jn75Zx03n7nt2SGccoX9E9jLOA62Hw=
|
||||
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:cliQ4HHsCo6xi2oWZYKWW4bly/Ory9FuTpFPRxj/mAg=
|
||||
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078/go.mod h1:g/V2Hjas6Z1UHUp4yIx6bATpNzJ7DYtD0FG3+xARWxs=
|
||||
git.sr.ht/~mariusor/lw v0.0.0-20240906100438-00d2184b2120 h1:OLxL9lel79BV3EHu/AMU+DtcuOnHnb3OjrLyF7NbE1w=
|
||||
git.sr.ht/~mariusor/lw v0.0.0-20240906100438-00d2184b2120/go.mod h1:kXJ4JsgGBu7IVBKlrVvGjSLJmpsAGqZwq/JU/kTUaLw=
|
||||
git.sr.ht/~mariusor/ssm v0.0.0-20240811085540-34f24cac52b7 h1:bCGvett+MiEDc5L+T9jByp671KnKRG/iJCCm0fc+21s=
|
||||
git.sr.ht/~mariusor/ssm v0.0.0-20240811085540-34f24cac52b7/go.mod h1:VApG24PG5Ij+tw5zpN5O61FSQU9gJK/cYQwFYM+kkwA=
|
||||
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
|
||||
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/carlmjohnson/be v0.23.2 h1:1QjPnPJhwGUjsD9+7h98EQlKsxnG5TV+nnEvk0wnkls=
|
||||
github.com/carlmjohnson/be v0.23.2/go.mod h1:KAgPUh0HpzWYZZI+IABdo80wTgY43YhbdsiLYAaSI/Q=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/go-ap/activitypub v0.0.0-20240910141749-b4b8c8aa484c h1:82lzmsy5Nr6JA6HcLRVxGfbdSoWfW45C6jnY3zFS7Ks=
|
||||
github.com/go-ap/activitypub v0.0.0-20240910141749-b4b8c8aa484c/go.mod h1:rpIPGre4qtTgSpVT0zz3hycAMuLtUt7BNngVNpyXhL8=
|
||||
github.com/go-ap/cache v0.0.0-20240910141827-94f8ac1a9133 h1:m4kbmmgtUwk0cSqqysf5aPwX4cd9Q2MEXCiZ+8sLAB0=
|
||||
github.com/go-ap/cache v0.0.0-20240910141827-94f8ac1a9133/go.mod h1:fFBwyje1EwOeMO588u+V0sND5SN94G6MhuNwQOrpPSA=
|
||||
github.com/go-ap/client v0.0.0-20240910141951-13a4f3c4fd53 h1:wHUTCltRHg+Uz24+Ym1Bz5AE/0mnIKjzbdcPU9MKH1Y=
|
||||
github.com/go-ap/client v0.0.0-20240910141951-13a4f3c4fd53/go.mod h1:9VAgCNIP146tYVV5mA1OyoMGpxIUo9DSx7XLZFcZin0=
|
||||
github.com/go-ap/errors v0.0.0-20240910140019-1e9d33cc1568 h1:eQEXAzWEijFbwtm/Hr2EtFbM0LvATRd1ltpDb+mfjQk=
|
||||
github.com/go-ap/errors v0.0.0-20240910140019-1e9d33cc1568/go.mod h1:Vkh+Z3f24K8nMsJKXo1FHn5ebPsXvB/WDH5JRtYqdNo=
|
||||
github.com/go-ap/fedbox v0.0.0-20240910163620-7bcedb2eb399 h1:exxqQ+fu5u8SQGLNh+26o7dJXetisjfCEgwERK4Pquw=
|
||||
github.com/go-ap/fedbox v0.0.0-20240910163620-7bcedb2eb399/go.mod h1:forbKJptQWYoG7HJesrzxeIgod0jCEBm6q9mlU0qTBY=
|
||||
github.com/go-ap/filters v0.0.0-20240910141936-c8f68cdf2bc9 h1:OYaAekA5CRlyERVY7iHKbj5HunEhbhk0dzIlPo8sVJg=
|
||||
github.com/go-ap/filters v0.0.0-20240910141936-c8f68cdf2bc9/go.mod h1:MhJ7+3WJ2/ckcVi+2I7awydLT6diYoZTz6FokpDIYLw=
|
||||
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73 h1:GMKIYXyXPGIp+hYiWOhfqK4A023HdgisDT4YGgf99mw=
|
||||
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73/go.mod h1:jyveZeGw5LaADntW+UEsMjl3IlIwk+DxlYNsbofQkGA=
|
||||
github.com/go-ap/processing v0.0.0-20240910151355-8284a5ce9c22 h1:tbMqrM1fxIKR0ml2DzPr7JI8h8io9gJMKQtpH/SMZ7k=
|
||||
github.com/go-ap/processing v0.0.0-20240910151355-8284a5ce9c22/go.mod h1:fUIzD9DAMXw1ZJN2PVLFU5mfqDibnPDj3e1d7cNxRGo=
|
||||
github.com/go-ap/storage-sqlite v0.0.0-20240910151457-20fa80d963aa h1:O1StIx92J3cXJNzcbvjGjtunvJVgpdBpKZL+48EgOUU=
|
||||
github.com/go-ap/storage-sqlite v0.0.0-20240910151457-20fa80d963aa/go.mod h1:KYODCEwUFfaGSwG22KBG1MNMVTkc278pfRMmZRqE9NA=
|
||||
github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
|
||||
github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/go-fed/httpsig v1.1.0 h1:9M+hb0jkEICD8/cAiNqEB66R87tTINszBRTjwjQzWcI=
|
||||
github.com/go-fed/httpsig v1.1.0/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo=
|
||||
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||
github.com/mariusor/qstring v0.0.0-20200204164351-5a99d46de39d h1:bkd9X98bkucj5wlCsgTYHPx4NYoc6tUzSbmyZXOrnl4=
|
||||
github.com/mariusor/qstring v0.0.0-20200204164351-5a99d46de39d/go.mod h1:WYcWf5qC9oospJOziIantsuqCcbWheB5zQ5FI60W3kU=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-sqlite3 v1.14.23 h1:gbShiuAP1W5j9UOksQ06aiiqPMxYecovVGwmTxWtuw0=
|
||||
github.com/mattn/go-sqlite3 v1.14.23/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
||||
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||
github.com/openshift/build-machinery-go v0.0.0-20200917070002-f171684f77ab/go.mod h1:b1BuldmJlbA/xYtdZvKi+7j5YGB44qJUJDZ9zwiNCfE=
|
||||
github.com/openshift/osin v1.0.2-0.20220317075346-0f4d38c6e53f h1:4da9vH8eDlJo58703cADj3FlsdnFRgsnfuwj/4lYXfY=
|
||||
github.com/openshift/osin v1.0.2-0.20220317075346-0f4d38c6e53f/go.mod h1:DoYehsADYGKlXTIvqyZVnopfJbWgT6UsQYf8ETt1vjw=
|
||||
github.com/openshift/osincli v0.0.0-20160924135400-fababb0555f2/go.mod h1:Riv9DbfKiX3y9ebcS4PHU4zLhVXu971+4jCVwKIue5M=
|
||||
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||
github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw=
|
||||
github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
|
||||
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
|
||||
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
|
||||
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
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=
|
||||
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
|
||||
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
|
||||
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
|
||||
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
||||
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
|
||||
golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
|
||||
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
|
||||
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/square/go-jose.v1 v1.1.2/go.mod h1:QpYS+a4WhS+DTlyQIi6Ka7MS3SuR9a055rgXNEe6EiA=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
|
||||
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
|
||||
modernc.org/gc/v3 v3.0.0-20240801135723-a856999a2e4a h1:CfbpOLEo2IwNzJdMvE8aiRbPMxoTpgAJeyePh0SmO8M=
|
||||
modernc.org/gc/v3 v3.0.0-20240801135723-a856999a2e4a/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4=
|
||||
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
|
||||
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
|
||||
modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E=
|
||||
modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU=
|
||||
modernc.org/sqlite v1.33.0 h1:WWkA/T2G17okiLGgKAj4/RMIvgyMT19yQ038160IeYk=
|
||||
modernc.org/sqlite v1.33.0/go.mod h1:9uQ9hF/pCZoYZK73D/ud5Z7cIRIILSZI8NdIemVMTX8=
|
||||
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
|
||||
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
|
||||
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||
3
imports/.gitignore
vendored
Normal file
3
imports/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
*
|
||||
!default.go
|
||||
!.gitignore
|
||||
5
imports/default.go
Normal file
5
imports/default.go
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
package imports
|
||||
|
||||
import (
|
||||
_ "codeberg.org/danjones000/combluotion/store/sqlite"
|
||||
)
|
||||
371
internal/testmocks/config/config_mock.go
Normal file
371
internal/testmocks/config/config_mock.go
Normal 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
|
||||
}
|
||||
2260
internal/testmocks/store/store_mock.go
Normal file
2260
internal/testmocks/store/store_mock.go
Normal file
File diff suppressed because it is too large
Load diff
2
storage/.gitignore
vendored
Normal file
2
storage/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
*
|
||||
!.gitignore
|
||||
43
store/factory.go
Normal file
43
store/factory.go
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
package store
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"codeberg.org/danjones000/combluotion/config"
|
||||
)
|
||||
|
||||
var ErrNoFactory = errors.New("unknown factory")
|
||||
|
||||
type StoreFactory func(config.Store) (Store, error)
|
||||
|
||||
var factories map[string]StoreFactory
|
||||
|
||||
func init() {
|
||||
factories = make(map[string]StoreFactory)
|
||||
}
|
||||
|
||||
func AddFactory(name string, f StoreFactory) {
|
||||
factories[name] = f
|
||||
}
|
||||
|
||||
func GetFactory(name string) StoreFactory {
|
||||
return factories[name]
|
||||
}
|
||||
|
||||
func MakeStore(name string, conf config.Config) (Store, error) {
|
||||
st, err := conf.Store(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if name == "" {
|
||||
name = st.Name()
|
||||
}
|
||||
|
||||
f, ok := factories[name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%w: %s", ErrNoFactory, name)
|
||||
}
|
||||
return f(st)
|
||||
}
|
||||
105
store/factory_test.go
Normal file
105
store/factory_test.go
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
package store
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
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) {
|
||||
th := setupFactoryTest(t)
|
||||
AddFactory("mock", th.fact)
|
||||
defer delete(factories, "mock")
|
||||
_, ok := factories["mock"]
|
||||
assert.True(t, ok)
|
||||
}
|
||||
|
||||
func TestGetFactoryNil(t *testing.T) {
|
||||
f := GetFactory("mock")
|
||||
assert.Nil(t, f)
|
||||
}
|
||||
|
||||
func TestGetFactoryNotNil(t *testing.T) {
|
||||
th := setupFactoryTest(t)
|
||||
AddFactory("mock", th.fact)
|
||||
defer delete(factories, "mock")
|
||||
f := GetFactory("mock")
|
||||
assert.NotNil(t, f)
|
||||
}
|
||||
|
||||
func TestMakeStoreError(t *testing.T) {
|
||||
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) {
|
||||
th := setupFactoryTest(t)
|
||||
th.conf.
|
||||
EXPECT().
|
||||
Store("mock").
|
||||
Return(nil, nil)
|
||||
AddFactory("mock", th.fact)
|
||||
defer delete(factories, "mock")
|
||||
s, e := MakeStore("mock", th.conf)
|
||||
assert.NotNil(t, s)
|
||||
assert.NoError(t, e)
|
||||
}
|
||||
|
||||
func TestMakeStoreNoName(t *testing.T) {
|
||||
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("", th.conf)
|
||||
assert.NotNil(t, s)
|
||||
assert.NoError(t, e)
|
||||
}
|
||||
|
||||
func TestMakeStoreConfError(t *testing.T) {
|
||||
th := setupFactoryTest(t)
|
||||
mockError := errors.New("leave me alone")
|
||||
th.conf.EXPECT().Store("mock").Return(nil, mockError)
|
||||
s, e := MakeStore("mock", th.conf)
|
||||
assert.Zero(t, s)
|
||||
assert.ErrorIs(t, e, mockError)
|
||||
|
||||
}
|
||||
38
store/sqlite/repo.go
Normal file
38
store/sqlite/repo.go
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
package sqlite
|
||||
|
||||
import (
|
||||
"codeberg.org/danjones000/combluotion/config"
|
||||
"codeberg.org/danjones000/combluotion/store"
|
||||
"github.com/go-ap/storage-sqlite"
|
||||
)
|
||||
|
||||
func init() {
|
||||
store.AddFactory("sqlite", MakeStore)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
return Repo{db}, nil
|
||||
}
|
||||
|
||||
type Repo struct {
|
||||
store.PartStore
|
||||
}
|
||||
|
||||
func (r Repo) Bootstrap(config.Config) error {
|
||||
// @todo
|
||||
return nil
|
||||
}
|
||||
46
store/store.go
Normal file
46
store/store.go
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
package store
|
||||
|
||||
import (
|
||||
"codeberg.org/danjones000/combluotion/config"
|
||||
st "github.com/go-ap/fedbox/storage"
|
||||
proc "github.com/go-ap/processing"
|
||||
"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
|
||||
// CreateClient stores the client in the database and returns an error, if something went wrong.
|
||||
CreateClient(c osin.Client) error
|
||||
// RemoveClient removes a client (identified by id) from the database. Returns an error if something went wrong.
|
||||
RemoveClient(id string) error
|
||||
}
|
||||
|
||||
type ClientLister interface {
|
||||
// ListClients lists existing clients
|
||||
ListClients() ([]osin.Client, error)
|
||||
GetClient(id string) (osin.Client, error)
|
||||
}
|
||||
|
||||
type Bootstrapper interface {
|
||||
// Bootstrap should initialize the data store so that it can be used.
|
||||
// This will be called every time the application starts, so it MUST be idempotent and doesn't delete existing data.
|
||||
// An option is to run migrations in this method.
|
||||
Bootstrap(config.Config) error
|
||||
}
|
||||
|
||||
type Store interface {
|
||||
Bootstrapper
|
||||
PartStore
|
||||
}
|
||||
|
||||
type PartStore interface {
|
||||
ClientSaver
|
||||
ClientLister
|
||||
proc.Store
|
||||
proc.KeyLoader
|
||||
osin.Storage
|
||||
st.MetadataTyper
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue