-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'feature/data-sources' into develop
- Loading branch information
Showing
15 changed files
with
432 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package inj | ||
|
||
// A Datasource is any external interface that provides an interface given a | ||
// string key. It's split into two fundamental components: the DatasourceReader | ||
// and the DatasourceWriter. For the purposes of automatic configuration via | ||
// dependency injection, a DatasourceReader is all that's required. | ||
// | ||
// Datasource paths are supplied by values in structfield tags (which are empty | ||
// for normal inj operation). Here's an example of a struct that will try to | ||
// fulfil its dependencies from a datasource: | ||
// | ||
// type MyStruct stuct { | ||
// SomeIntVal int `inj:"some.path.in.a.datasource"` | ||
// } | ||
// | ||
// When trying to connect the dependency on an instance of the struct above, inj will | ||
// poll any available DatasourceReaders in the graph by calling their Read() function | ||
// with the string argument "some.path.in.a.datasource". If the function doesn't return | ||
// an error, then the resultant value will be used for the dependency injection. | ||
// | ||
// A struct tag may contain multiple datasource paths, separated by commas. The paths | ||
// will be polled in order of their appearance in the code, and the value from the first | ||
// DatasourceReader that doesn't return an error on its Read() function will be used to | ||
// meet the dependency. | ||
// | ||
// DatasourceWriters function in a similar way: when a value is set on an instance of a | ||
// struct via inj's dependency injection, any associated DatasourceWriters' Write() functions | ||
// are called for each datasource path. | ||
// | ||
type Datasource interface { | ||
DatasourceReader | ||
DatasourceWriter | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package inj | ||
|
||
// A datasource reader provides an object from a datasource, identified by a | ||
// given string key. Refer to the documentation for the Datasource interface for more information. | ||
type DatasourceReader interface { | ||
Read(string) (interface{}, error) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package inj | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
) | ||
|
||
/////////////////////////////////////////////////////////////// | ||
// A mock DatasourceReader implementation | ||
/////////////////////////////////////////////////////////////// | ||
|
||
type MockDatasourceReader struct { | ||
stack map[string]interface{} | ||
} | ||
|
||
func NewMockDatasourceReader(data ...map[string]interface{}) *MockDatasourceReader { | ||
|
||
d := &MockDatasourceReader{} | ||
|
||
d.stack = make(map[string]interface{}) | ||
|
||
for _, datum := range data { | ||
for k, v := range datum { | ||
d.stack[k] = v | ||
} | ||
} | ||
|
||
return d | ||
} | ||
|
||
func (d *MockDatasourceReader) Read(key string) (interface{}, error) { | ||
|
||
if value, exists := d.stack[key]; exists { | ||
return value, nil | ||
} | ||
|
||
return nil, fmt.Errorf("No stack entry for '%s'", key) | ||
} | ||
|
||
/////////////////////////////////////////////////////////////// | ||
// Unit tests for graph implementation | ||
/////////////////////////////////////////////////////////////// | ||
|
||
func Test_TheDatasourceReaderWritesToTheDepdendency(t *testing.T) { | ||
|
||
dep := dataSourceDep{} | ||
ds := newMockDataSourceWithValues(t) | ||
g := NewGraph() | ||
|
||
g.AddDatasource(ds) | ||
g.Provide(&dep) | ||
|
||
assertNoGraphErrors(t, g) | ||
|
||
if g, e := dep.StringValue, DEFAULT_STRING; g != e { | ||
t.Errorf("Expected string '%s', got '%s'", e, g) | ||
} | ||
|
||
if dep.FuncValue == nil { | ||
t.Errorf("Didn't get expected function instance") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package inj | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
) | ||
|
||
/////////////////////////////////////////////////////////////// | ||
// A mock DatasourceReader and DatasourceWriter implementation | ||
/////////////////////////////////////////////////////////////// | ||
|
||
type MockDatasource struct { | ||
stack map[string]interface{} | ||
} | ||
|
||
func NewMockDatasource() Datasource { | ||
|
||
d := &MockDatasource{} | ||
|
||
d.stack = make(map[string]interface{}) | ||
|
||
return d | ||
} | ||
|
||
func (d *MockDatasource) Read(key string) (interface{}, error) { | ||
|
||
if value, exists := d.stack[key]; exists { | ||
return value, nil | ||
} | ||
|
||
return nil, fmt.Errorf("No stack entry for '%s'", key) | ||
} | ||
|
||
func (d *MockDatasource) Write(key string, value interface{}) error { | ||
|
||
d.stack[key] = value | ||
|
||
return nil | ||
} | ||
|
||
/////////////////////////////////////////////////////////////// | ||
// A mock specific dependency implementation for testing | ||
/////////////////////////////////////////////////////////////// | ||
|
||
type dataSourceDep struct { | ||
StringValue string `inj:"datasource.string"` | ||
FuncValue FuncType `inj:"datasource.func"` | ||
IntValue int `inj:"datasource.int"` | ||
} | ||
|
||
func newMockDataSourceWithValues(t *testing.T) Datasource { | ||
|
||
d := NewMockDatasource() | ||
|
||
if e := d.Write("datasource.string", DEFAULT_STRING); e != nil { | ||
t.Fatalf("newMockDataSourceWithValues: Datasource.Write: %s", e) | ||
} | ||
|
||
if e := d.Write("datasource.func", funcInstance); e != nil { | ||
t.Fatalf("newMockDataSourceWithValues: Datasource.Write: %s", e) | ||
} | ||
|
||
// Try and integer value expressed as a float | ||
if e := d.Write("datasource.int", 16.01); e != nil { | ||
t.Fatalf("newMockDataSourceWithValues: Datasource.Write: %s", e) | ||
} | ||
|
||
return d | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package inj | ||
|
||
// A datasource reader sends an object to a datasource, identified by a | ||
// given string key. Refer to the documentation for the Datasource interface for more information. | ||
type DatasourceWriter interface { | ||
Write(string, interface{}) error | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
package inj | ||
|
||
import "testing" | ||
|
||
/////////////////////////////////////////////////////////////// | ||
// A mock DatasourceWriter implementation | ||
/////////////////////////////////////////////////////////////// | ||
|
||
type MockDatasourceWriter struct { | ||
stack map[string]interface{} | ||
} | ||
|
||
func NewMockDatasourceWriter(data ...map[string]interface{}) *MockDatasourceWriter { | ||
|
||
d := &MockDatasourceWriter{} | ||
|
||
d.stack = make(map[string]interface{}) | ||
|
||
for _, datum := range data { | ||
for k, v := range datum { | ||
d.stack[k] = v | ||
} | ||
} | ||
|
||
return d | ||
} | ||
|
||
func (d *MockDatasourceWriter) Write(key string, value interface{}) error { | ||
|
||
d.stack[key] = value | ||
|
||
return nil | ||
} | ||
|
||
func (d *MockDatasourceWriter) Assert(t *testing.T, key string, value interface{}) { | ||
|
||
v, exists := d.stack[key] | ||
|
||
if !exists { | ||
t.Fatalf("MockDatasourceWriter.Assert: Key '%s' doesn't exist", key) | ||
} | ||
|
||
if v != value { | ||
t.Fatalf("MockDatasourceWriter.Assert: key %s doesn't match (%v, %v)", key, v, value) | ||
} | ||
} | ||
|
||
func (d *MockDatasourceWriter) AssertMap(t *testing.T, data map[string]interface{}) { | ||
|
||
for k, v := range data { | ||
d.Assert(t, k, v) | ||
} | ||
} | ||
|
||
/////////////////////////////////////////////////////////////// | ||
// Unit tests for graph implementation | ||
/////////////////////////////////////////////////////////////// | ||
|
||
type datasourceWriterDep struct { | ||
IntVal int `inj:"datasource.writer.int"` | ||
StringVal string `inj:"datasource.writer.string"` | ||
} | ||
|
||
func Test_DatasourceReaderWriterLoopInGraph(t *testing.T) { | ||
|
||
expected_values := map[string]interface{}{ | ||
"datasource.writer.int": 10, | ||
"datasource.writer.string": DEFAULT_STRING, | ||
} | ||
|
||
reader := NewMockDatasourceReader(expected_values) | ||
writer := NewMockDatasourceWriter() | ||
dep := datasourceWriterDep{} | ||
g := NewGraph() | ||
|
||
g.AddDatasource(reader, writer) | ||
g.Provide(&dep) | ||
|
||
assertNoGraphErrors(t, g) | ||
|
||
writer.AssertMap(t, expected_values) | ||
} | ||
|
||
func Test_DatasourceWriterWritesWithoutAReader(t *testing.T) { | ||
|
||
expected_values := map[string]interface{}{ | ||
"datasource.writer.int": 10, | ||
"datasource.writer.string": DEFAULT_STRING, | ||
} | ||
|
||
writer := NewMockDatasourceWriter() | ||
dep := datasourceWriterDep{} | ||
g := NewGraph() | ||
|
||
g.AddDatasource(writer) | ||
g.Provide( | ||
expected_values["datasource.writer.int"], | ||
expected_values["datasource.writer.string"], | ||
&dep, | ||
) | ||
|
||
assertNoGraphErrors(t, g) | ||
|
||
writer.AssertMap(t, expected_values) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.