move config unions to common code (#224)
* move config unions to common code The configuration union handlers in Storage and Account overlapped significantly in behavior. Moving those helpers into a common code folder was requested. Although the behavior was similar across the files, the types were not, requiring the addition of generics to solve the need.
This commit is contained in:
parent
2b65ff80f2
commit
0bd23ab2ab
21
src/internal/common/configs.go
Normal file
21
src/internal/common/configs.go
Normal file
@ -0,0 +1,21 @@
|
||||
package common
|
||||
|
||||
type StringConfigurer interface {
|
||||
StringConfig() (map[string]string, error)
|
||||
}
|
||||
|
||||
// UnionStringConfigs unions all provided configurers into a single
|
||||
// map[string]string matching type.
|
||||
func UnionStringConfigs(cfgs ...StringConfigurer) (map[string]string, error) {
|
||||
union := map[string]string{}
|
||||
for _, cfg := range cfgs {
|
||||
c, err := cfg.StringConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for k, v := range c {
|
||||
union[k] = v
|
||||
}
|
||||
}
|
||||
return union, nil
|
||||
}
|
||||
72
src/internal/common/configs_test.go
Normal file
72
src/internal/common/configs_test.go
Normal file
@ -0,0 +1,72 @@
|
||||
package common_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"github.com/alcionai/corso/internal/common"
|
||||
)
|
||||
|
||||
type CommonConfigsSuite struct {
|
||||
suite.Suite
|
||||
}
|
||||
|
||||
func TestCommonConfigsSuite(t *testing.T) {
|
||||
suite.Run(t, new(CommonConfigsSuite))
|
||||
}
|
||||
|
||||
const (
|
||||
keyExpect = "expect"
|
||||
keyExpect2 = "expect2"
|
||||
)
|
||||
|
||||
type stringConfig struct {
|
||||
expectA string
|
||||
err error
|
||||
}
|
||||
|
||||
func (c stringConfig) StringConfig() (map[string]string, error) {
|
||||
return map[string]string{keyExpect: c.expectA}, c.err
|
||||
}
|
||||
|
||||
type stringConfig2 struct {
|
||||
expectB string
|
||||
err error
|
||||
}
|
||||
|
||||
func (c stringConfig2) StringConfig() (map[string]string, error) {
|
||||
return map[string]string{keyExpect2: c.expectB}, c.err
|
||||
}
|
||||
|
||||
func (suite *CommonConfigsSuite) TestUnionConfigs_string() {
|
||||
table := []struct {
|
||||
name string
|
||||
ac stringConfig
|
||||
bc stringConfig2
|
||||
errCheck assert.ErrorAssertionFunc
|
||||
}{
|
||||
{"no error", stringConfig{keyExpect, nil}, stringConfig2{keyExpect2, nil}, assert.NoError},
|
||||
{"tc error", stringConfig{keyExpect, assert.AnError}, stringConfig2{keyExpect2, nil}, assert.Error},
|
||||
{"fc error", stringConfig{keyExpect, nil}, stringConfig2{keyExpect2, assert.AnError}, assert.Error},
|
||||
}
|
||||
for _, test := range table {
|
||||
suite.T().Run(test.name, func(t *testing.T) {
|
||||
cs, err := common.UnionStringConfigs(test.ac, test.bc)
|
||||
test.errCheck(t, err)
|
||||
// remaining tests depend on error-free state
|
||||
if test.ac.err != nil || test.bc.err != nil {
|
||||
return
|
||||
}
|
||||
assert.Equalf(t,
|
||||
test.ac.expectA,
|
||||
cs[keyExpect],
|
||||
"expected unioned config to have value [%s] at key [%s], got [%s]", test.ac.expectA, keyExpect, cs[keyExpect])
|
||||
assert.Equalf(t,
|
||||
test.bc.expectB,
|
||||
cs[keyExpect2],
|
||||
"expected unioned config to have value [%s] at key [%s], got [%s]", test.bc.expectB, keyExpect2, cs[keyExpect2])
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,10 @@
|
||||
package account
|
||||
|
||||
import "errors"
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/alcionai/corso/internal/common"
|
||||
)
|
||||
|
||||
type accountProvider int
|
||||
|
||||
@ -15,39 +19,18 @@ var (
|
||||
errMissingRequired = errors.New("missing required storage configuration")
|
||||
)
|
||||
|
||||
type (
|
||||
config map[string]string
|
||||
configurer interface {
|
||||
Config() (config, error)
|
||||
}
|
||||
)
|
||||
|
||||
// Account defines an account provider, along with any credentials
|
||||
// and identifiers requried to set up or communicate with that provider.
|
||||
type Account struct {
|
||||
Provider accountProvider
|
||||
Config config
|
||||
Config map[string]string
|
||||
}
|
||||
|
||||
// NewAccount aggregates all the supplied configurations into a single configuration
|
||||
func NewAccount(p accountProvider, cfgs ...configurer) (Account, error) {
|
||||
cs, err := unionConfigs(cfgs...)
|
||||
func NewAccount(p accountProvider, cfgs ...common.StringConfigurer) (Account, error) {
|
||||
cs, err := common.UnionStringConfigs(cfgs...)
|
||||
return Account{
|
||||
Provider: p,
|
||||
Config: cs,
|
||||
}, err
|
||||
}
|
||||
|
||||
func unionConfigs(cfgs ...configurer) (config, error) {
|
||||
union := config{}
|
||||
for _, cfg := range cfgs {
|
||||
c, err := cfg.Config()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for k, v := range c {
|
||||
union[k] = v
|
||||
}
|
||||
}
|
||||
return union, nil
|
||||
}
|
||||
|
||||
@ -12,8 +12,8 @@ type testConfig struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (c testConfig) Config() (config, error) {
|
||||
return config{"expect": c.expect}, c.err
|
||||
func (c testConfig) StringConfig() (map[string]string, error) {
|
||||
return map[string]string{"expect": c.expect}, c.err
|
||||
}
|
||||
|
||||
type AccountSuite struct {
|
||||
@ -55,43 +55,3 @@ func (suite *AccountSuite) TestNewAccount() {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type fooConfig struct {
|
||||
foo string
|
||||
err error
|
||||
}
|
||||
|
||||
func (c fooConfig) Config() (config, error) {
|
||||
return config{"foo": c.foo}, c.err
|
||||
}
|
||||
|
||||
func (suite *AccountSuite) TestUnionConfigs() {
|
||||
table := []struct {
|
||||
name string
|
||||
tc testConfig
|
||||
fc fooConfig
|
||||
errCheck assert.ErrorAssertionFunc
|
||||
}{
|
||||
{"no error", testConfig{"test", nil}, fooConfig{"foo", nil}, assert.NoError},
|
||||
{"tc error", testConfig{"test", assert.AnError}, fooConfig{"foo", nil}, assert.Error},
|
||||
{"fc error", testConfig{"test", nil}, fooConfig{"foo", assert.AnError}, assert.Error},
|
||||
}
|
||||
for _, test := range table {
|
||||
suite.T().Run(test.name, func(t *testing.T) {
|
||||
cs, err := unionConfigs(test.tc, test.fc)
|
||||
test.errCheck(t, err)
|
||||
// remaining tests depend on error-free state
|
||||
if test.tc.err != nil || test.fc.err != nil {
|
||||
return
|
||||
}
|
||||
assert.Equalf(t,
|
||||
test.tc.expect,
|
||||
cs["expect"],
|
||||
"expected unioned config to have value [%s] at key [expect], got [%s]", test.tc.expect, cs["expect"])
|
||||
assert.Equalf(t,
|
||||
test.fc.foo,
|
||||
cs["foo"],
|
||||
"expected unioned config to have value [%s] at key [foo], got [%s]", test.fc.foo, cs["foo"])
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,8 +24,8 @@ const (
|
||||
// (todo) TenantID = "TENANT_ID"
|
||||
)
|
||||
|
||||
func (c M365Config) Config() (config, error) {
|
||||
cfg := config{
|
||||
func (c M365Config) StringConfig() (map[string]string, error) {
|
||||
cfg := map[string]string{
|
||||
keyM365ClientID: c.ClientID,
|
||||
keyM365ClientSecret: c.ClientSecret,
|
||||
keyM365TenantID: c.TenantID,
|
||||
|
||||
@ -29,7 +29,7 @@ var goodM365Config = account.M365Config{
|
||||
|
||||
func (suite *M365CfgSuite) TestM365Config_Config() {
|
||||
m365 := goodM365Config
|
||||
c, err := m365.Config()
|
||||
c, err := m365.StringConfig()
|
||||
require.NoError(suite.T(), err)
|
||||
|
||||
table := []struct {
|
||||
|
||||
@ -15,8 +15,8 @@ const (
|
||||
keyCommonCorsoPassword = "common_corsoPassword"
|
||||
)
|
||||
|
||||
func (c CommonConfig) Config() (config, error) {
|
||||
cfg := config{
|
||||
func (c CommonConfig) StringConfig() (map[string]string, error) {
|
||||
cfg := map[string]string{
|
||||
keyCommonCorsoPassword: c.CorsoPassword,
|
||||
}
|
||||
return cfg, c.validate()
|
||||
|
||||
@ -26,7 +26,7 @@ var goodCommonConfig = storage.CommonConfig{
|
||||
|
||||
func (suite *CommonCfgSuite) TestCommonConfig_Config() {
|
||||
cfg := goodCommonConfig
|
||||
c, err := cfg.Config()
|
||||
c, err := cfg.StringConfig()
|
||||
assert.NoError(suite.T(), err)
|
||||
|
||||
table := []struct {
|
||||
|
||||
@ -31,8 +31,8 @@ const (
|
||||
Prefix = "prefix"
|
||||
)
|
||||
|
||||
func (c S3Config) Config() (config, error) {
|
||||
cfg := config{
|
||||
func (c S3Config) StringConfig() (map[string]string, error) {
|
||||
cfg := map[string]string{
|
||||
keyS3AccessKey: c.AccessKey,
|
||||
keyS3Bucket: c.Bucket,
|
||||
keyS3Endpoint: c.Endpoint,
|
||||
|
||||
@ -31,7 +31,7 @@ var goodS3Config = storage.S3Config{
|
||||
|
||||
func (suite *S3CfgSuite) TestS3Config_Config() {
|
||||
s3 := goodS3Config
|
||||
c, err := s3.Config()
|
||||
c, err := s3.StringConfig()
|
||||
assert.NoError(suite.T(), err)
|
||||
|
||||
table := []struct {
|
||||
|
||||
@ -3,6 +3,8 @@ package storage
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/alcionai/corso/internal/common"
|
||||
)
|
||||
|
||||
type storageProvider int
|
||||
@ -18,43 +20,22 @@ var (
|
||||
errMissingRequired = errors.New("missing required storage configuration")
|
||||
)
|
||||
|
||||
type (
|
||||
config map[string]any
|
||||
configurer interface {
|
||||
Config() (config, error)
|
||||
}
|
||||
)
|
||||
|
||||
// Storage defines a storage provider, along with any configuration
|
||||
// requried to set up or communicate with that provider.
|
||||
type Storage struct {
|
||||
Provider storageProvider
|
||||
Config config
|
||||
Config map[string]string
|
||||
}
|
||||
|
||||
// NewStorage aggregates all the supplied configurations into a single configuration.
|
||||
func NewStorage(p storageProvider, cfgs ...configurer) (Storage, error) {
|
||||
cs, err := unionConfigs(cfgs...)
|
||||
func NewStorage(p storageProvider, cfgs ...common.StringConfigurer) (Storage, error) {
|
||||
cs, err := common.UnionStringConfigs(cfgs...)
|
||||
return Storage{
|
||||
Provider: p,
|
||||
Config: cs,
|
||||
}, err
|
||||
}
|
||||
|
||||
func unionConfigs(cfgs ...configurer) (config, error) {
|
||||
union := config{}
|
||||
for _, cfg := range cfgs {
|
||||
c, err := cfg.Config()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for k, v := range c {
|
||||
union[k] = v
|
||||
}
|
||||
}
|
||||
return union, nil
|
||||
}
|
||||
|
||||
// Helper for parsing the values in a config object.
|
||||
// If the value is nil or not a string, returns an empty string.
|
||||
func orEmptyString(v any) string {
|
||||
|
||||
@ -12,8 +12,8 @@ type testConfig struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (c testConfig) Config() (config, error) {
|
||||
return config{"expect": c.expect}, c.err
|
||||
func (c testConfig) StringConfig() (map[string]string, error) {
|
||||
return map[string]string{"expect": c.expect}, c.err
|
||||
}
|
||||
|
||||
type StorageSuite struct {
|
||||
@ -55,43 +55,3 @@ func (suite *StorageSuite) TestNewStorage() {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type fooConfig struct {
|
||||
foo string
|
||||
err error
|
||||
}
|
||||
|
||||
func (c fooConfig) Config() (config, error) {
|
||||
return config{"foo": c.foo}, c.err
|
||||
}
|
||||
|
||||
func (suite *StorageSuite) TestUnionConfigs() {
|
||||
table := []struct {
|
||||
name string
|
||||
tc testConfig
|
||||
fc fooConfig
|
||||
errCheck assert.ErrorAssertionFunc
|
||||
}{
|
||||
{"no error", testConfig{"test", nil}, fooConfig{"foo", nil}, assert.NoError},
|
||||
{"tc error", testConfig{"test", assert.AnError}, fooConfig{"foo", nil}, assert.Error},
|
||||
{"fc error", testConfig{"test", nil}, fooConfig{"foo", assert.AnError}, assert.Error},
|
||||
}
|
||||
for _, test := range table {
|
||||
suite.T().Run(test.name, func(t *testing.T) {
|
||||
cs, err := unionConfigs(test.tc, test.fc)
|
||||
test.errCheck(t, err)
|
||||
// remaining tests depend on error-free state
|
||||
if test.tc.err != nil || test.fc.err != nil {
|
||||
return
|
||||
}
|
||||
assert.Equalf(t,
|
||||
test.tc.expect,
|
||||
cs["expect"],
|
||||
"expected unioned config to have value [%s] at key [expect], got [%s]", test.tc.expect, cs["expect"])
|
||||
assert.Equalf(t,
|
||||
test.fc.foo,
|
||||
cs["foo"],
|
||||
"expected unioned config to have value [%s] at key [foo], got [%s]", test.fc.foo, cs["foo"])
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user