Merge pull request #859 from cloudskiff/fea/fail_from_incorrect
do not fail if one multiple from is incorrectmain
commit
f8a4ba9968
|
@ -224,7 +224,7 @@ func scanRun(opts *pkg.ScanOptions) error {
|
||||||
|
|
||||||
scanner := remote.NewScanner(remoteLibrary, alerter, remote.ScannerOptions{Deep: opts.Deep}, driftIgnore)
|
scanner := remote.NewScanner(remoteLibrary, alerter, remote.ScannerOptions{Deep: opts.Deep}, driftIgnore)
|
||||||
|
|
||||||
iacSupplier, err := supplier.GetIACSupplier(opts.From, providerLibrary, opts.BackendOptions, iacProgress, resFactory, driftIgnore)
|
iacSupplier, err := supplier.GetIACSupplier(opts.From, providerLibrary, opts.BackendOptions, iacProgress, alerter, resFactory, driftIgnore)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
package iac
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StateReadingError struct {
|
||||||
|
errors []error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStateReadingError() *StateReadingError {
|
||||||
|
return &StateReadingError{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StateReadingError) Add(err error) {
|
||||||
|
s.errors = append(s.errors, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StateReadingError) Error() string {
|
||||||
|
var err strings.Builder
|
||||||
|
_, _ = fmt.Fprint(&err, "There were errors reading your states files : \n")
|
||||||
|
for _, e := range s.errors {
|
||||||
|
_, _ = fmt.Fprintf(&err, " - %s\n", e.Error())
|
||||||
|
}
|
||||||
|
return err.String()
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
package supplier
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
"github.com/cloudskiff/driftctl/pkg/iac"
|
||||||
|
"github.com/cloudskiff/driftctl/pkg/parallel"
|
||||||
|
"github.com/cloudskiff/driftctl/pkg/resource"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IacChainSupplier struct {
|
||||||
|
suppliers []resource.Supplier
|
||||||
|
runner *parallel.ParallelRunner
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIacChainSupplier() *IacChainSupplier {
|
||||||
|
return &IacChainSupplier{
|
||||||
|
runner: parallel.NewParallelRunner(context.TODO(), int64(runtime.NumCPU())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *IacChainSupplier) AddSupplier(supplier resource.Supplier) {
|
||||||
|
r.suppliers = append(r.suppliers, supplier)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *IacChainSupplier) Resources() ([]*resource.Resource, error) {
|
||||||
|
|
||||||
|
for _, supplier := range r.suppliers {
|
||||||
|
sup := supplier
|
||||||
|
r.runner.Run(func() (interface{}, error) {
|
||||||
|
resources, err := sup.Resources()
|
||||||
|
return &result{err, resources}, nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
results := make([]*resource.Resource, 0)
|
||||||
|
isSuccess := false
|
||||||
|
retrieveError := iac.NewStateReadingError()
|
||||||
|
ReadLoop:
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case supplierResult, ok := <-r.runner.Read():
|
||||||
|
if !ok || supplierResult == nil {
|
||||||
|
break ReadLoop
|
||||||
|
}
|
||||||
|
// Type cannot be invalid as return type is enforced
|
||||||
|
// in run function on top
|
||||||
|
result, _ := supplierResult.(*result)
|
||||||
|
|
||||||
|
if result.err != nil {
|
||||||
|
retrieveError.Add(result.err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
isSuccess = true
|
||||||
|
results = append(results, result.res...)
|
||||||
|
case <-r.runner.DoneChan():
|
||||||
|
break ReadLoop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.runner.Err() != nil {
|
||||||
|
return nil, r.runner.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isSuccess {
|
||||||
|
// only fail if all suppliers failed
|
||||||
|
return nil, retrieveError
|
||||||
|
}
|
||||||
|
|
||||||
|
return results, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type result struct {
|
||||||
|
err error
|
||||||
|
res []*resource.Resource
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
package supplier
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/cloudskiff/driftctl/pkg/resource"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIacChainSupplier_Resources(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
initSuppliers func(suppliers *[]resource.Supplier)
|
||||||
|
want []*resource.Resource
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "All failed",
|
||||||
|
initSuppliers: func(suppliers *[]resource.Supplier) {
|
||||||
|
sup := &resource.MockSupplier{}
|
||||||
|
sup.On("Resources").Return(nil, errors.New("1"))
|
||||||
|
*suppliers = append(*suppliers, sup)
|
||||||
|
|
||||||
|
sup = &resource.MockSupplier{}
|
||||||
|
sup.On("Resources").Return(nil, errors.New("2"))
|
||||||
|
*suppliers = append(*suppliers, sup)
|
||||||
|
|
||||||
|
sup = &resource.MockSupplier{}
|
||||||
|
sup.On("Resources").Return(nil, errors.New("3"))
|
||||||
|
*suppliers = append(*suppliers, sup)
|
||||||
|
},
|
||||||
|
want: nil,
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Partial failed",
|
||||||
|
initSuppliers: func(suppliers *[]resource.Supplier) {
|
||||||
|
sup := &resource.MockSupplier{}
|
||||||
|
sup.On("Resources").Return(nil, errors.New("1"))
|
||||||
|
*suppliers = append(*suppliers, sup)
|
||||||
|
|
||||||
|
sup = &resource.MockSupplier{}
|
||||||
|
sup.On("Resources").Return(nil, errors.New("2"))
|
||||||
|
*suppliers = append(*suppliers, sup)
|
||||||
|
|
||||||
|
sup = &resource.MockSupplier{}
|
||||||
|
sup.On("Resources").Return([]*resource.Resource{
|
||||||
|
&resource.Resource{
|
||||||
|
Id: "ID",
|
||||||
|
Type: "TYPE",
|
||||||
|
Attrs: nil,
|
||||||
|
},
|
||||||
|
}, nil)
|
||||||
|
*suppliers = append(*suppliers, sup)
|
||||||
|
},
|
||||||
|
want: []*resource.Resource{
|
||||||
|
&resource.Resource{
|
||||||
|
Id: "ID",
|
||||||
|
Type: "TYPE",
|
||||||
|
Attrs: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
r := NewIacChainSupplier()
|
||||||
|
suppliers := make([]resource.Supplier, 0)
|
||||||
|
tt.initSuppliers(&suppliers)
|
||||||
|
|
||||||
|
for _, supplier := range suppliers {
|
||||||
|
r.AddSupplier(supplier)
|
||||||
|
}
|
||||||
|
|
||||||
|
got, err := r.Resources()
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("Resources() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("Resources() got = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ package supplier
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/cloudskiff/driftctl/pkg/alerter"
|
||||||
"github.com/cloudskiff/driftctl/pkg/filter"
|
"github.com/cloudskiff/driftctl/pkg/filter"
|
||||||
"github.com/cloudskiff/driftctl/pkg/iac/terraform/state/backend"
|
"github.com/cloudskiff/driftctl/pkg/iac/terraform/state/backend"
|
||||||
"github.com/cloudskiff/driftctl/pkg/output"
|
"github.com/cloudskiff/driftctl/pkg/output"
|
||||||
|
@ -34,10 +35,11 @@ func GetIACSupplier(configs []config.SupplierConfig,
|
||||||
library *terraform.ProviderLibrary,
|
library *terraform.ProviderLibrary,
|
||||||
backendOpts *backend.Options,
|
backendOpts *backend.Options,
|
||||||
progress output.Progress,
|
progress output.Progress,
|
||||||
|
alerter *alerter.Alerter,
|
||||||
factory resource.ResourceFactory,
|
factory resource.ResourceFactory,
|
||||||
filter filter.Filter) (resource.Supplier, error) {
|
filter filter.Filter) (resource.Supplier, error) {
|
||||||
|
|
||||||
chainSupplier := resource.NewChainSupplier()
|
chainSupplier := NewIacChainSupplier()
|
||||||
for _, config := range configs {
|
for _, config := range configs {
|
||||||
if !IsSupplierSupported(config.Key) {
|
if !IsSupplierSupported(config.Key) {
|
||||||
return nil, errors.Errorf("Unsupported supplier '%s'", config.Key)
|
return nil, errors.Errorf("Unsupported supplier '%s'", config.Key)
|
||||||
|
@ -49,7 +51,7 @@ func GetIACSupplier(configs []config.SupplierConfig,
|
||||||
var err error
|
var err error
|
||||||
switch config.Key {
|
switch config.Key {
|
||||||
case state.TerraformStateReaderSupplier:
|
case state.TerraformStateReaderSupplier:
|
||||||
supplier, err = state.NewReader(config, library, backendOpts, progress, deserializer, filter)
|
supplier, err = state.NewReader(config, library, backendOpts, progress, alerter, deserializer, filter)
|
||||||
default:
|
default:
|
||||||
return nil, errors.Errorf("Unsupported supplier '%s'", config.Key)
|
return nil, errors.Errorf("Unsupported supplier '%s'", config.Key)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/cloudskiff/driftctl/pkg/alerter"
|
||||||
"github.com/cloudskiff/driftctl/pkg/filter"
|
"github.com/cloudskiff/driftctl/pkg/filter"
|
||||||
"github.com/cloudskiff/driftctl/pkg/iac/config"
|
"github.com/cloudskiff/driftctl/pkg/iac/config"
|
||||||
"github.com/cloudskiff/driftctl/pkg/iac/terraform/state/backend"
|
"github.com/cloudskiff/driftctl/pkg/iac/terraform/state/backend"
|
||||||
|
@ -90,10 +91,12 @@ func TestGetIACSupplier(t *testing.T) {
|
||||||
|
|
||||||
repo := resource.InitFakeSchemaRepository("aws", "3.19.0")
|
repo := resource.InitFakeSchemaRepository("aws", "3.19.0")
|
||||||
factory := terraform.NewTerraformResourceFactory(repo)
|
factory := terraform.NewTerraformResourceFactory(repo)
|
||||||
|
alerter := alerter.NewAlerter()
|
||||||
|
|
||||||
testFilter := &filter.MockFilter{}
|
testFilter := &filter.MockFilter{}
|
||||||
|
|
||||||
_, err := GetIACSupplier(tt.args.config, terraform.NewProviderLibrary(), tt.args.options, progress, factory, testFilter)
|
_, err := GetIACSupplier(tt.args.config, terraform.NewProviderLibrary(), tt.args.options, progress, alerter, factory, testFilter)
|
||||||
|
|
||||||
if tt.wantErr != nil && err.Error() != tt.wantErr.Error() {
|
if tt.wantErr != nil && err.Error() != tt.wantErr.Error() {
|
||||||
t.Errorf("GetIACSupplier() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("GetIACSupplier() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
return
|
return
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
package state
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type StateReadingAlert struct {
|
||||||
|
key string
|
||||||
|
err string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStateReadingAlert(key string, err error) *StateReadingAlert {
|
||||||
|
return &StateReadingAlert{key: key, err: err.Error()}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StateReadingAlert) Message() string {
|
||||||
|
return fmt.Sprintf("Your analysis may be incomplete. There was an error reading state file '%s': %s", s.key, s.err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StateReadingAlert) ShouldIgnoreResource() bool {
|
||||||
|
return false
|
||||||
|
}
|
|
@ -23,6 +23,10 @@ func NewFileEnumerator(config config.SupplierConfig) *FileEnumerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *FileEnumerator) Origin() string {
|
||||||
|
return s.config.String()
|
||||||
|
}
|
||||||
|
|
||||||
func (s *FileEnumerator) Enumerate() ([]string, error) {
|
func (s *FileEnumerator) Enumerate() ([]string, error) {
|
||||||
path := s.config.Path
|
path := s.config.Path
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,10 @@ func NewS3Enumerator(config config.SupplierConfig) *S3Enumerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *S3Enumerator) Origin() string {
|
||||||
|
return s.config.String()
|
||||||
|
}
|
||||||
|
|
||||||
func (s *S3Enumerator) Enumerate() ([]string, error) {
|
func (s *S3Enumerator) Enumerate() ([]string, error) {
|
||||||
bucketPath := strings.Split(s.config.Path, "/")
|
bucketPath := strings.Split(s.config.Path, "/")
|
||||||
if len(bucketPath) < 2 {
|
if len(bucketPath) < 2 {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type StateEnumerator interface {
|
type StateEnumerator interface {
|
||||||
|
Origin() string
|
||||||
Enumerate() ([]string, error)
|
Enumerate() ([]string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,10 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/cloudskiff/driftctl/pkg/alerter"
|
||||||
"github.com/cloudskiff/driftctl/pkg/filter"
|
"github.com/cloudskiff/driftctl/pkg/filter"
|
||||||
|
"github.com/cloudskiff/driftctl/pkg/iac"
|
||||||
"github.com/cloudskiff/driftctl/pkg/output"
|
"github.com/cloudskiff/driftctl/pkg/output"
|
||||||
"github.com/fatih/color"
|
|
||||||
"github.com/hashicorp/terraform/addrs"
|
"github.com/hashicorp/terraform/addrs"
|
||||||
"github.com/hashicorp/terraform/states"
|
"github.com/hashicorp/terraform/states"
|
||||||
"github.com/hashicorp/terraform/states/statefile"
|
"github.com/hashicorp/terraform/states/statefile"
|
||||||
|
@ -39,6 +40,7 @@ type TerraformStateReader struct {
|
||||||
backendOptions *backend.Options
|
backendOptions *backend.Options
|
||||||
progress output.Progress
|
progress output.Progress
|
||||||
filter filter.Filter
|
filter filter.Filter
|
||||||
|
alerter *alerter.Alerter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *TerraformStateReader) initReader() error {
|
func (r *TerraformStateReader) initReader() error {
|
||||||
|
@ -46,8 +48,8 @@ func (r *TerraformStateReader) initReader() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewReader(config config.SupplierConfig, library *terraform.ProviderLibrary, backendOpts *backend.Options, progress output.Progress, deserializer *resource.Deserializer, filter filter.Filter) (*TerraformStateReader, error) {
|
func NewReader(config config.SupplierConfig, library *terraform.ProviderLibrary, backendOpts *backend.Options, progress output.Progress, alerter *alerter.Alerter, deserializer *resource.Deserializer, filter filter.Filter) (*TerraformStateReader, error) {
|
||||||
reader := TerraformStateReader{library: library, config: config, deserializer: deserializer, backendOptions: backendOpts, progress: progress, filter: filter}
|
reader := TerraformStateReader{library: library, config: config, deserializer: deserializer, backendOptions: backendOpts, progress: progress, alerter: alerter, filter: filter}
|
||||||
err := reader.initReader()
|
err := reader.initReader()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -221,34 +223,43 @@ func (r *TerraformStateReader) retrieveForState(path string) ([]*resource.Resour
|
||||||
r.progress.Inc()
|
r.progress.Inc()
|
||||||
values, err := r.retrieve()
|
values, err := r.retrieve()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, errors.Wrap(err, r.config.String())
|
||||||
}
|
}
|
||||||
return r.decode(values)
|
decode, err := r.decode(values)
|
||||||
|
return decode, errors.Wrap(err, r.config.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *TerraformStateReader) retrieveMultiplesStates() ([]*resource.Resource, error) {
|
func (r *TerraformStateReader) retrieveMultiplesStates() ([]*resource.Resource, error) {
|
||||||
keys, err := r.enumerator.Enumerate()
|
keys, err := r.enumerator.Enumerate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
r.alerter.SendAlert("", NewStateReadingAlert(r.enumerator.Origin(), err))
|
||||||
|
return nil, errors.Wrap(err, r.config.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
logrus.WithFields(logrus.Fields{
|
logrus.WithFields(logrus.Fields{
|
||||||
"keys": keys,
|
"keys": keys,
|
||||||
}).Debug("Enumerated keys")
|
}).Debug("Enumerated keys")
|
||||||
|
|
||||||
results := make([]*resource.Resource, 0)
|
results := make([]*resource.Resource, 0)
|
||||||
|
isSuccess := false
|
||||||
|
readingError := iac.NewStateReadingError()
|
||||||
|
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
resources, err := r.retrieveForState(key)
|
resources, err := r.retrieveForState(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if _, ok := err.(*UnsupportedVersionError); ok {
|
readingError.Add(err)
|
||||||
color.New(color.Bold, color.FgYellow).Printf("WARNING: %s\n", err)
|
r.alerter.SendAlert("", NewStateReadingAlert(key, err))
|
||||||
continue
|
continue
|
||||||
}
|
|
||||||
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
isSuccess = true
|
||||||
results = append(results, resources...)
|
results = append(results, resources...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !isSuccess {
|
||||||
|
// all key failed, throw an error
|
||||||
|
return results, readingError
|
||||||
|
}
|
||||||
|
|
||||||
return results, nil
|
return results, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
package resource
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"runtime"
|
|
||||||
|
|
||||||
"github.com/cloudskiff/driftctl/pkg/parallel"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ChainSupplier struct {
|
|
||||||
suppliers []Supplier
|
|
||||||
runner *parallel.ParallelRunner
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewChainSupplier() *ChainSupplier {
|
|
||||||
return &ChainSupplier{
|
|
||||||
runner: parallel.NewParallelRunner(context.TODO(), int64(runtime.NumCPU())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *ChainSupplier) AddSupplier(supplier Supplier) {
|
|
||||||
r.suppliers = append(r.suppliers, supplier)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *ChainSupplier) Resources() ([]*Resource, error) {
|
|
||||||
|
|
||||||
for _, supplier := range r.suppliers {
|
|
||||||
sup := supplier
|
|
||||||
r.runner.Run(func() (interface{}, error) {
|
|
||||||
return sup.Resources()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
results := make([]*Resource, 0)
|
|
||||||
|
|
||||||
ReadLoop:
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case supplierResult, ok := <-r.runner.Read():
|
|
||||||
if !ok || supplierResult == nil {
|
|
||||||
break ReadLoop
|
|
||||||
}
|
|
||||||
// Type cannot be invalid as return type is enforced
|
|
||||||
// by Supplier interface
|
|
||||||
resources, _ := supplierResult.([]*Resource)
|
|
||||||
results = append(results, resources...)
|
|
||||||
case <-r.runner.DoneChan():
|
|
||||||
break ReadLoop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if r.runner.Err() != nil {
|
|
||||||
return nil, r.runner.Err()
|
|
||||||
}
|
|
||||||
|
|
||||||
return results, nil
|
|
||||||
}
|
|
|
@ -1,89 +0,0 @@
|
||||||
package resource_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/cloudskiff/driftctl/pkg/resource"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestChainSupplier_Resources(t *testing.T) {
|
|
||||||
|
|
||||||
assert := assert.New(t)
|
|
||||||
|
|
||||||
fakeTestSupplier := resource.MockSupplier{}
|
|
||||||
fakeTestSupplier.On("Resources").Return(
|
|
||||||
[]*resource.Resource{
|
|
||||||
&resource.Resource{
|
|
||||||
Id: "fake-supplier-1_fake-resource-1",
|
|
||||||
},
|
|
||||||
&resource.Resource{
|
|
||||||
Id: "fake-supplier-1_fake-resource-2",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
nil,
|
|
||||||
).Once()
|
|
||||||
|
|
||||||
anotherFakeTestSupplier := resource.MockSupplier{}
|
|
||||||
anotherFakeTestSupplier.On("Resources").Return(
|
|
||||||
[]*resource.Resource{
|
|
||||||
&resource.Resource{
|
|
||||||
Id: "fake-supplier-2_fake-resource-1",
|
|
||||||
},
|
|
||||||
&resource.Resource{
|
|
||||||
Id: "fake-supplier-2_fake-resource-2",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
nil,
|
|
||||||
).Once()
|
|
||||||
|
|
||||||
chain := resource.NewChainSupplier()
|
|
||||||
chain.AddSupplier(&fakeTestSupplier)
|
|
||||||
chain.AddSupplier(&anotherFakeTestSupplier)
|
|
||||||
|
|
||||||
res, err := chain.Resources()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
anotherFakeTestSupplier.AssertExpectations(t)
|
|
||||||
fakeTestSupplier.AssertExpectations(t)
|
|
||||||
assert.Len(res, 4)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestChainSupplier_Resources_WithError(t *testing.T) {
|
|
||||||
|
|
||||||
assert := assert.New(t)
|
|
||||||
|
|
||||||
fakeTestSupplier := resource.MockSupplier{}
|
|
||||||
fakeTestSupplier.
|
|
||||||
On("Resources").
|
|
||||||
Return([]*resource.Resource{
|
|
||||||
&resource.Resource{
|
|
||||||
Id: "fake-supplier-1_fake-resource-1",
|
|
||||||
},
|
|
||||||
&resource.Resource{
|
|
||||||
Id: "fake-supplier-1_fake-resource-2",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
nil,
|
|
||||||
)
|
|
||||||
|
|
||||||
anotherFakeTestSupplier := resource.MockSupplier{}
|
|
||||||
anotherFakeTestSupplier.
|
|
||||||
On("Resources").
|
|
||||||
Return(nil, errors.New("error from another supplier")).
|
|
||||||
Once()
|
|
||||||
|
|
||||||
chain := resource.NewChainSupplier()
|
|
||||||
chain.AddSupplier(&fakeTestSupplier)
|
|
||||||
chain.AddSupplier(&anotherFakeTestSupplier)
|
|
||||||
|
|
||||||
res, err := chain.Resources()
|
|
||||||
|
|
||||||
anotherFakeTestSupplier.AssertExpectations(t)
|
|
||||||
assert.Nil(res)
|
|
||||||
assert.Equal("error from another supplier", err.Error())
|
|
||||||
}
|
|
Loading…
Reference in New Issue