config: RawConfig works, plus tests

This commit is contained in:
Mitchell Hashimoto 2014-06-12 17:24:55 -07:00
parent a24b30b8d2
commit e445f8db38
2 changed files with 120 additions and 2 deletions

View File

@ -1,5 +1,10 @@
package config
import (
"github.com/mitchellh/copystructure"
"github.com/mitchellh/reflectwalk"
)
// UnknownVariableValue is a sentinel value that can be used
// to denote that the value of a variable is unknown at this time.
// RawConfig uses this information to build up data about
@ -18,6 +23,23 @@ const UnknownVariableValue = "74D93920-ED26-11E3-AC10-0800200C9A66"
type RawConfig struct {
Raw map[string]interface{}
Variables map[string]InterpolatedVariable
config map[string]interface{}
unknownKeys []string
}
// NewRawConfig creates a new RawConfig structure and populates the
// publicly readable struct fields.
func NewRawConfig(raw map[string]interface{}) (*RawConfig, error) {
walker := new(variableDetectWalker)
if err := reflectwalk.Walk(raw, walker); err != nil {
return nil, err
}
return &RawConfig{
Raw: raw,
Variables: walker.Variables,
}, nil
}
// Interpolate uses the given mapping of variable values and uses
@ -27,7 +49,21 @@ type RawConfig struct {
// Any prior calls to Interpolate are replaced with this one.
//
// If a variable key is missing, this will panic.
func (r *RawConfig) Interpolate(map[string]string) {
func (r *RawConfig) Interpolate(vs map[string]string) error {
config, err := copystructure.Copy(r.Raw)
if err != nil {
return err
}
w := &variableReplaceWalker{Values: vs}
r.config = config.(map[string]interface{})
err = reflectwalk.Walk(r.config, w)
if err != nil {
return err
}
r.unknownKeys = w.UnknownKeys
return nil
}
// Config returns the entire configuration with the variables
@ -42,5 +78,11 @@ func (r *RawConfig) Interpolate(map[string]string) {
// structure will always successfully decode into its ultimate
// structure using something like mapstructure.
func (r *RawConfig) Config() map[string]interface{} {
return nil
return r.config
}
// UnknownKeys returns the keys of the configuration that are unknown
// because they had interpolated variables that must be computed.
func (r *RawConfig) UnknownKeys() []string {
return r.unknownKeys
}

View File

@ -1 +1,77 @@
package config
import (
"reflect"
"testing"
)
func TestNewRawConfig(t *testing.T) {
raw := map[string]interface{}{
"foo": "${var.bar}",
}
rc, err := NewRawConfig(raw)
if err != nil {
t.Fatalf("err: %s", err)
}
if len(rc.Variables) != 1 {
t.Fatalf("bad: %#v", rc.Variables)
}
}
func TestRawConfig(t *testing.T) {
raw := map[string]interface{}{
"foo": "${var.bar}",
}
rc, err := NewRawConfig(raw)
if err != nil {
t.Fatalf("err: %s", err)
}
vars := map[string]string{"var.bar": "baz"}
if err := rc.Interpolate(vars); err != nil {
t.Fatalf("err: %s", err)
}
actual := rc.Config()
expected := map[string]interface{}{
"foo": "baz",
}
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad: %#v", actual)
}
if len(rc.UnknownKeys()) != 0 {
t.Fatalf("bad: %#v", rc.UnknownKeys())
}
}
func TestRawConfig_unknown(t *testing.T) {
raw := map[string]interface{}{
"foo": "${var.bar}",
}
rc, err := NewRawConfig(raw)
if err != nil {
t.Fatalf("err: %s", err)
}
vars := map[string]string{"var.bar": UnknownVariableValue}
if err := rc.Interpolate(vars); err != nil {
t.Fatalf("err: %s", err)
}
actual := rc.Config()
expected := map[string]interface{}{}
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad: %#v", actual)
}
expectedKeys := []string{"foo"}
if !reflect.DeepEqual(rc.UnknownKeys(), expectedKeys) {
t.Fatalf("bad: %#v", rc.UnknownKeys())
}
}