Implement Cobra CLI tooling, Viper config tooling (#336)

* start pulling out + replacing urfave and config

* replace many many instances of config

* move more stuff => viper

* properly remove urfave

* move some flags to root command

* add testrig commands to root

* alias config file keys

* start adding cli parsing tests

* reorder viper init

* remove config path alias

* fmt

* change config file keys to non-nested

* we're more or less in business now

* tidy up the common func

* go fmt

* get tests passing again

* add note about the cliparsing tests

* reorganize

* update docs with changes

* structure cmd dir better

* rename + move some files around

* fix dangling comma
This commit is contained in:
tobi
2021-12-07 13:31:39 +01:00
committed by GitHub
parent 182b4eea73
commit 0884f89431
487 changed files with 46667 additions and 8831 deletions

View File

@@ -18,9 +18,103 @@
package testrig
import "github.com/superseriousbusiness/gotosocial/internal/config"
import (
"reflect"
// NewTestConfig returns a config initialized with test defaults
func NewTestConfig() *config.Config {
return config.TestDefault()
"github.com/coreos/go-oidc/v3/oidc"
"github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/config"
)
// InitTestConfig resets + initializes the viper configuration with test defaults.
func InitTestConfig() {
// reset viper to an empty state
viper.Reset()
// get the field names of config.Keys
keyFields := reflect.VisibleFields(reflect.TypeOf(config.Keys))
// get the field values of config.Keys
keyValues := reflect.ValueOf(config.Keys)
// get the field values of TestDefaults
testDefaults := reflect.ValueOf(TestDefaults)
// for each config field...
for _, field := range keyFields {
// the viper config key should be the value of the key
key, ok := keyValues.FieldByName(field.Name).Interface().(string)
if !ok {
panic("could not convert config.Keys value to string")
}
// the value should be the test default corresponding to the given fieldName
value := testDefaults.FieldByName(field.Name).Interface()
// actually set the value in viper -- this will override everything
viper.Set(key, value)
}
}
// TestDefaults returns a Values struct with values set that are suitable for local testing.
var TestDefaults = config.Values{
LogLevel: "trace",
ApplicationName: "gotosocial",
ConfigPath: "",
Host: "localhost:8080",
AccountDomain: "localhost:8080",
Protocol: "http",
BindAddress: "127.0.0.1",
Port: 8080,
TrustedProxies: []string{"127.0.0.1/32"},
DbType: "sqlite",
DbAddress: ":memory:",
DbPort: 5432,
DbUser: "postgres",
DbPassword: "postgres",
DbDatabase: "postgres",
WebTemplateBaseDir: "./web/template/",
WebAssetBaseDir: "./web/assets/",
AccountsRegistrationOpen: true,
AccountsApprovalRequired: true,
AccountsReasonRequired: true,
MediaImageMaxSize: 1048576, // 1mb
MediaVideoMaxSize: 5242880, // 5mb
MediaDescriptionMinChars: 0,
MediaDescriptionMaxChars: 500,
StorageBackend: "local",
StorageBasePath: "/gotosocial/storage",
StorageServeProtocol: "http",
StorageServeHost: "localhost:8080",
StorageServeBasePath: "/fileserver",
StatusesMaxChars: 5000,
StatusesCWMaxChars: 100,
StatusesPollMaxOptions: 6,
StatusesPollOptionMaxChars: 50,
StatusesMediaMaxFiles: 6,
LetsEncryptEnabled: false,
LetsEncryptPort: 0,
LetsEncryptCertDir: "",
LetsEncryptEmailAddress: "",
OIDCEnabled: false,
OIDCIdpName: "",
OIDCSkipVerification: false,
OIDCIssuer: "",
OIDCClientID: "",
OIDCClientSecret: "",
OIDCScopes: []string{oidc.ScopeOpenID, "profile", "email", "groups"},
SMTPHost: "",
SMTPPort: 0,
SMTPUsername: "",
SMTPPassword: "",
SMTPFrom: "GoToSocial",
}

View File

@@ -24,6 +24,8 @@ import (
"strconv"
"github.com/sirupsen/logrus"
"github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/db/bundb"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
@@ -66,27 +68,23 @@ var testModels = []interface{}{
// If the environment variable GTS_DB_PORT is set, it will take that
// value as the port instead.
func NewTestDB() db.DB {
config := NewTestConfig()
alternateAddress := os.Getenv("GTS_DB_ADDRESS")
if alternateAddress != "" {
config.DBConfig.Address = alternateAddress
if alternateAddress := os.Getenv("GTS_DB_ADDRESS"); alternateAddress != "" {
viper.Set(config.Keys.DbAddress, alternateAddress)
}
alternateDBType := os.Getenv("GTS_DB_TYPE")
if alternateDBType != "" {
config.DBConfig.Type = alternateDBType
if alternateDBType := os.Getenv("GTS_DB_TYPE"); alternateDBType != "" {
viper.Set(config.Keys.DbType, alternateDBType)
}
alternateDBPort := os.Getenv("GTS_DB_PORT")
if alternateDBPort != "" {
if alternateDBPort := os.Getenv("GTS_DB_PORT"); alternateDBPort != "" {
port, err := strconv.ParseInt(alternateDBPort, 10, 64)
if err != nil {
panic(err)
}
config.DBConfig.Port = int(port)
viper.Set(config.Keys.DbPort, port)
}
testDB, err := bundb.NewBunDBService(context.Background(), config)
testDB, err := bundb.NewBunDBService(context.Background())
if err != nil {
logrus.Panic(err)
}

View File

@@ -18,7 +18,11 @@
package testrig
import "github.com/superseriousbusiness/gotosocial/internal/email"
import (
"github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/email"
)
// NewEmailSender returns a noop email sender that won't make any remote calls.
//
@@ -26,6 +30,8 @@ import "github.com/superseriousbusiness/gotosocial/internal/email"
// the map, with email address of the recipient as the key, and the value as the
// parsed email message as it would have been sent.
func NewEmailSender(templateBaseDir string, sentEmails map[string]string) email.Sender {
viper.Set(config.Keys.WebTemplateBaseDir, templateBaseDir)
var sendCallback func(toAddress string, message string)
if sentEmails != nil {
@@ -34,7 +40,7 @@ func NewEmailSender(templateBaseDir string, sentEmails map[string]string) email.
}
}
s, err := email.NewNoopSender(templateBaseDir, sendCallback)
s, err := email.NewNoopSender(sendCallback)
if err != nil {
panic(err)
}

View File

@@ -7,5 +7,5 @@ import (
// NewTestFederatingDB returns a federating DB with the underlying db
func NewTestFederatingDB(db db.DB) federatingdb.DB {
return federatingdb.New(db, NewTestConfig())
return federatingdb.New(db)
}

View File

@@ -27,5 +27,5 @@ import (
// NewTestFederator returns a federator with the given database and (mock!!) transport controller.
func NewTestFederator(db db.DB, tc transport.Controller, storage *kv.KVStore) federation.Federator {
return federation.NewFederator(db, NewTestFederatingDB(db), tc, NewTestConfig(), NewTestTypeConverter(db), NewTestMediaHandler(db, storage))
return federation.NewFederator(db, NewTestFederatingDB(db), tc, NewTestTypeConverter(db), NewTestMediaHandler(db, storage))
}

View File

@@ -26,5 +26,5 @@ import (
// NewTestMediaHandler returns a media handler with the default test config, and the given db and storage.
func NewTestMediaHandler(db db.DB, storage *kv.KVStore) media.Handler {
return media.New(NewTestConfig(), db, storage)
return media.New(db, storage)
}

View File

@@ -28,5 +28,5 @@ import (
// NewTestProcessor returns a Processor suitable for testing purposes
func NewTestProcessor(db db.DB, storage *kv.KVStore, federator federation.Federator, emailSender email.Sender) processing.Processor {
return processing.NewProcessor(NewTestConfig(), NewTestTypeConverter(db), federator, NewTestOauthServer(db), NewTestMediaHandler(db, storage), storage, NewTestTimelineManager(db), db, emailSender)
return processing.NewProcessor(NewTestTypeConverter(db), federator, NewTestOauthServer(db), NewTestMediaHandler(db, storage), storage, NewTestTimelineManager(db), db, emailSender)
}

View File

@@ -27,7 +27,7 @@ import (
// NewTestRouter returns a Router suitable for testing
func NewTestRouter(db db.DB) router.Router {
r, err := router.New(context.Background(), NewTestConfig(), db)
r, err := router.New(context.Background(), db)
if err != nil {
panic(err)
}

View File

@@ -7,5 +7,5 @@ import (
// NewTestTimelineManager retuts a new timeline.Manager, suitable for testing, using the given db.
func NewTestTimelineManager(db db.DB) timeline.Manager {
return timeline.NewManager(db, NewTestTypeConverter(db), NewTestConfig())
return timeline.NewManager(db, NewTestTypeConverter(db))
}

View File

@@ -39,7 +39,7 @@ import (
// PER TEST rather than per suite, so that the do function can be set on a test by test (or even more granular)
// basis.
func NewTestTransportController(client pub.HttpClient, db db.DB) transport.Controller {
return transport.NewController(NewTestConfig(), db, &federation.Clock{}, client)
return transport.NewController(db, &federation.Clock{}, client)
}
// NewMockHTTPClient returns a client that conforms to the pub.HttpClient interface,

View File

@@ -25,5 +25,5 @@ import (
// NewTestTypeConverter returned a type converter with the given db and the default test config
func NewTestTypeConverter(db db.DB) typeutils.TypeConverter {
return typeutils.NewConverter(NewTestConfig(), db)
return typeutils.NewConverter(db)
}