This commit is contained in:
46
test/etcd.go
Normal file
46
test/etcd.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
client "go.etcd.io/etcd/client/v3"
|
||||
)
|
||||
|
||||
func NewEtcd(ctx context.Context) (*client.Client, error) {
|
||||
dsn, ok := os.LookupEnv("FDEVS_CONFIG_ETCD_HOST")
|
||||
if !ok {
|
||||
dsn = "127.0.0.1:2379"
|
||||
}
|
||||
|
||||
et, err := client.New(client.Config{
|
||||
Endpoints: []string{dsn},
|
||||
DialTimeout: time.Second,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
values := map[string]string{
|
||||
"fdevs/config/db_dsn": "pgsql://user@pass:127.0.0.1:5432",
|
||||
"fdevs/config/duration": "12m",
|
||||
"fdevs/config/port": "8080",
|
||||
"fdevs/config/maintain": "true",
|
||||
"fdevs/config/start_at": "2020-01-02T15:04:05Z",
|
||||
"fdevs/config/percent": "0.064",
|
||||
"fdevs/config/count": "2020",
|
||||
"fdevs/config/int64": "2021",
|
||||
"fdevs/config/uint64": "2022",
|
||||
"fdevs/config/config": ConfigJSON,
|
||||
}
|
||||
|
||||
for name, val := range values {
|
||||
_, err = et.KV.Put(ctx, name, val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return et, nil
|
||||
}
|
||||
1038
test/fixture/config.ini
Normal file
1038
test/fixture/config.ini
Normal file
File diff suppressed because it is too large
Load Diff
16
test/fixture/config.json
Normal file
16
test/fixture/config.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"app": {
|
||||
"name": {
|
||||
"var": [
|
||||
"name"
|
||||
],
|
||||
"title": "config title",
|
||||
"timeout": "1m",
|
||||
"success": true
|
||||
}
|
||||
},
|
||||
"cfg": {
|
||||
"duration": 1260000000000,
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
31
test/fixture/config.toml
Normal file
31
test/fixture/config.toml
Normal file
@@ -0,0 +1,31 @@
|
||||
title = "TOML Example"
|
||||
|
||||
[owner]
|
||||
name = "Tom Preston-Werner"
|
||||
dob = 1979-05-27T07:32:00-08:00 # First class dates
|
||||
|
||||
[database]
|
||||
server = "192.168.1.1"
|
||||
ports = [ 8001, 8001, 8002 ]
|
||||
connection_max = 5000
|
||||
enabled = true
|
||||
|
||||
[servers]
|
||||
|
||||
# Indentation (tabs and/or spaces) is allowed but not required
|
||||
[servers.alpha]
|
||||
ip = "10.0.0.1"
|
||||
dc = "eqdc10"
|
||||
|
||||
[servers.beta]
|
||||
ip = "10.0.0.2"
|
||||
dc = "eqdc10"
|
||||
|
||||
[clients]
|
||||
data = [ ["gamma", "delta"], [1, 2] ]
|
||||
|
||||
# Line breaks are OK when inside arrays
|
||||
hosts = [
|
||||
"alpha",
|
||||
"omega"
|
||||
]
|
||||
12
test/fixture/config.yaml
Normal file
12
test/fixture/config.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
app:
|
||||
name:
|
||||
var:
|
||||
- test
|
||||
bool_var: true
|
||||
duration_var: 21m
|
||||
empty_var:
|
||||
url_var: "http://google.com/"
|
||||
time_var: "2020-01-02T15:04:05Z"
|
||||
cfg:
|
||||
duration: 21m
|
||||
enabled: true
|
||||
17
test/helpers.go
Normal file
17
test/helpers.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func FixturePath(file string) string {
|
||||
path := "fixture/"
|
||||
|
||||
_, filename, _, ok := runtime.Caller(0)
|
||||
if ok {
|
||||
path = filepath.Dir(filename) + "/" + path
|
||||
}
|
||||
|
||||
return path + file
|
||||
}
|
||||
16
test/ini.go
Normal file
16
test/ini.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
func NewINI() *ini.File {
|
||||
f, err := ini.Load(FixturePath("config.ini"))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return f
|
||||
}
|
||||
15
test/json.go
Normal file
15
test/json.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
)
|
||||
|
||||
func ReadFile(file string) []byte {
|
||||
data, err := ioutil.ReadFile(FixturePath(file))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
150
test/provider_suite.go
Normal file
150
test/provider_suite.go
Normal file
@@ -0,0 +1,150 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"gitoa.ru/go-4devs/config"
|
||||
)
|
||||
|
||||
const (
|
||||
DSN = "pgsql://user@pass:127.0.0.1:5432"
|
||||
Namespace = "fdevs"
|
||||
AppName = "config"
|
||||
)
|
||||
|
||||
func Run(t *testing.T, provider config.Provider, read []Read) {
|
||||
t.Helper()
|
||||
|
||||
prov := &ProviderSuite{
|
||||
provider: provider,
|
||||
read: read,
|
||||
}
|
||||
suite.Run(t, prov)
|
||||
}
|
||||
|
||||
type ProviderSuite struct {
|
||||
suite.Suite
|
||||
provider config.Provider
|
||||
read []Read
|
||||
}
|
||||
|
||||
type Read struct {
|
||||
Key config.Key
|
||||
Assert func(t *testing.T, v config.Value)
|
||||
}
|
||||
|
||||
const ConfigJSON = `{"duration":1260000000000,"enabled":true}`
|
||||
|
||||
type Config struct {
|
||||
Duration time.Duration
|
||||
Enabled bool
|
||||
}
|
||||
|
||||
func NewReadConfig(key string) Read {
|
||||
ex := &Config{
|
||||
Duration: 21 * time.Minute,
|
||||
Enabled: true,
|
||||
}
|
||||
|
||||
return NewReadUnmarshal(key, ex, &Config{})
|
||||
}
|
||||
|
||||
func NewReadUnmarshal(key string, expected, target interface{}) Read {
|
||||
return Read{
|
||||
Key: config.Key{
|
||||
Namespace: "fdevs",
|
||||
AppName: "config",
|
||||
Name: key,
|
||||
},
|
||||
Assert: func(t *testing.T, v config.Value) {
|
||||
t.Helper()
|
||||
require.NoErrorf(t, v.Unmarshal(target), "unmarshal")
|
||||
require.Equal(t, expected, target, "unmarshal")
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func Time(value string) time.Time {
|
||||
t, _ := time.Parse(time.RFC3339, value)
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
// nolint: cyclop
|
||||
func NewRead(key string, expected interface{}) Read {
|
||||
return Read{
|
||||
Key: config.Key{
|
||||
Namespace: "fdevs",
|
||||
AppName: "config",
|
||||
Name: key,
|
||||
},
|
||||
Assert: func(t *testing.T, v config.Value) {
|
||||
t.Helper()
|
||||
var (
|
||||
val interface{}
|
||||
err error
|
||||
short interface{}
|
||||
)
|
||||
switch expected.(type) {
|
||||
case bool:
|
||||
val, err = v.ParseBool()
|
||||
short = v.Bool()
|
||||
case int:
|
||||
val, err = v.ParseInt()
|
||||
short = v.Int()
|
||||
case int64:
|
||||
val, err = v.ParseInt64()
|
||||
short = v.Int64()
|
||||
case uint:
|
||||
val, err = v.ParseUint()
|
||||
short = v.Uint()
|
||||
case uint64:
|
||||
val, err = v.ParseUint64()
|
||||
short = v.Uint64()
|
||||
case string:
|
||||
val, err = v.ParseString()
|
||||
short = v.String()
|
||||
case float64:
|
||||
val, err = v.ParseFloat64()
|
||||
short = v.Float64()
|
||||
case time.Duration:
|
||||
val, err = v.ParseDuration()
|
||||
short = v.Duration()
|
||||
case time.Time:
|
||||
val, err = v.ParseTime()
|
||||
short = v.Time()
|
||||
default:
|
||||
require.Fail(t, "unexpected type", "type:%+T", expected)
|
||||
}
|
||||
|
||||
require.Equalf(t, val, short, "type:%T", expected)
|
||||
require.NoErrorf(t, err, "type:%T", expected)
|
||||
require.Equalf(t, expected, val, "type:%T", expected)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (ps *ProviderSuite) TestReadKeys() {
|
||||
ctx := context.Background()
|
||||
|
||||
for _, read := range ps.read {
|
||||
val, err := ps.provider.Read(ctx, read.Key)
|
||||
require.NoError(ps.T(), err, read.Key.String())
|
||||
read.Assert(ps.T(), val.Value)
|
||||
}
|
||||
}
|
||||
|
||||
func LoadConfig(t *testing.T, path string) []byte {
|
||||
t.Helper()
|
||||
|
||||
file, err := ioutil.ReadFile(filepath.Clean(path))
|
||||
require.NoError(t, err)
|
||||
|
||||
return file
|
||||
}
|
||||
89
test/vault.go
Normal file
89
test/vault.go
Normal file
@@ -0,0 +1,89 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/hashicorp/vault/api"
|
||||
)
|
||||
|
||||
const token = "dev"
|
||||
|
||||
func NewVault() (*api.Client, error) {
|
||||
address, ok := os.LookupEnv("VAULT_DEV_LISTEN_ADDRESS")
|
||||
if !ok {
|
||||
address = "http://127.0.0.1:8200"
|
||||
}
|
||||
|
||||
tokenID, ok := os.LookupEnv("VAULT_DEV_ROOT_TOKEN_ID")
|
||||
if !ok {
|
||||
tokenID = token
|
||||
}
|
||||
|
||||
cl, err := api.NewClient(&api.Config{
|
||||
Address: address,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cl.SetToken(tokenID)
|
||||
|
||||
values := map[string]map[string]interface{}{
|
||||
"database": {
|
||||
"duration": 1260000000000,
|
||||
"enabled": true,
|
||||
},
|
||||
"db": {
|
||||
"dsn": DSN,
|
||||
"timeout": "60s",
|
||||
},
|
||||
"example": {
|
||||
"dsn": DSN,
|
||||
"timeout": "60s",
|
||||
},
|
||||
}
|
||||
|
||||
for name, val := range values {
|
||||
if err := create(address, tokenID, name, val); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return cl, nil
|
||||
}
|
||||
|
||||
func create(host, token, path string, data map[string]interface{}) error {
|
||||
type Req struct {
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
b, err := json.Marshal(Req{Data: data})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
body := bytes.NewBuffer(b)
|
||||
|
||||
req, err := http.NewRequestWithContext(
|
||||
context.Background(),
|
||||
http.MethodPost,
|
||||
host+"/v1/secret/data/fdevs/config/"+path,
|
||||
body,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req.Header.Set("X-Vault-Token", token)
|
||||
|
||||
res, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return res.Body.Close()
|
||||
}
|
||||
Reference in New Issue
Block a user