github.com/keikoproj/manny@v0.0.0-20210726112440-8571e4c99ced/configurator/configurator_test.go (about)

     1  package configurator
     2  
     3  import (
     4  	"context"
     5  	"io/ioutil"
     6  	"os"
     7  	"path/filepath"
     8  	"runtime"
     9  	"strings"
    10  	"testing"
    11  
    12  	"github.com/aws/aws-sdk-go/service/s3"
    13  	"github.com/stretchr/testify/mock"
    14  	"github.com/keikoproj/cloudresource-manager/api/v1alpha1"
    15  	"go.uber.org/zap"
    16  	"go.uber.org/zap/zapcore"
    17  
    18  	"github.com/keikoproj/manny/configurator/mocks"
    19  )
    20  
    21  func TestExamples(t *testing.T) {
    22  	var table = []struct {
    23  		name   string
    24  		path   string
    25  		length int
    26  		error  bool
    27  	}{
    28  		{"nested configuration", "./examples/nested/aws/usw2/", 6, false},
    29  		{"static configuration", "./examples/static/aws/usw2/", 3, false},
    30  		{"static configuration", "./examples/static/aws/use2/", 2, false},
    31  		{"s3 configuration", "./examples/s3/aws/usw2/", 2, false},
    32  		{"http configuration", "./examples/http/aws/usw2/", 1, false},
    33  		{"resolvers configuration", "./examples/resolvers/", 2, false},
    34  		{"error on circular dependencies", "./tests/circular-dependency/", 0, true},
    35  		{"error on greater than 10 base references", "./tests/base-reference-cap/", 0, true},
    36  		{ "don't create stack for empty resources", "./examples/complex/missing-resources/", 0, false},
    37  	}
    38  
    39  	for _, tt := range table {
    40  		t.Run(tt.name, func(t *testing.T) {
    41  			// set working directory as manny root directory
    42  			_, filename, _, _ := runtime.Caller(0)
    43  			wd := filepath.Join(filename, "../..")
    44  			err := os.Chdir(wd)
    45  
    46  			// handle relative and absolute paths
    47  			if strings.HasPrefix(tt.path, ".") {
    48  				tt.path = filepath.Join(wd, tt.path)
    49  			}
    50  
    51  			// show debug logs if a test fails
    52  			log, err := initTestLogger()
    53  			if err != nil {
    54  				t.Error(err)
    55  			}
    56  
    57  			// mock s3 api
    58  			mockS3 := new(mocks.S3API)
    59  
    60  			config := New(Config{
    61  				Path:     tt.path,
    62  				Logger:   log,
    63  				S3Client: mockS3,
    64  			})
    65  
    66  			if tt.name == "s3 configuration" {
    67  				ctx := context.Background()
    68  				testFileBody := `{
    69  									"Resources" : {
    70  										"HelloBucket" : {
    71  											"Type" : "AWS::S3::Bucket",
    72  											"Properties" : {
    73  											   "AccessControl" : "PublicRead"
    74  											}
    75  										}
    76  									}
    77  								}`
    78  				contentLength := int64(len(testFileBody))
    79  				s3GetObjectOutput := &s3.GetObjectOutput{
    80  					Body:          ioutil.NopCloser(strings.NewReader(testFileBody)),
    81  					ContentLength: &contentLength,
    82  				}
    83  				mockS3.On("GetObjectWithContext", ctx, mock.Anything, mock.Anything).
    84  					Return(s3GetObjectOutput, nil)
    85  			}
    86  
    87  			deployments, err := config.CreateDeployments()
    88  			if err != nil && !tt.error {
    89  				t.Error(err)
    90  			}
    91  
    92  			if len(deployments) != tt.length {
    93  				t.Errorf("Incorrect length got: %d want: %d\n", len(deployments), tt.length)
    94  			}
    95  			invalidConfig :=config.mannyConfigValidate("foo")
    96  			if invalidConfig{
    97  				t.Errorf("mannyConfigValidate failed")
    98  			}
    99  		})
   100  	}
   101  }
   102  
   103  func Test_CloudResourcesValidate(t *testing.T) {
   104  	var table = []struct {
   105  		name      string
   106  		resources CloudResources
   107  		error     bool
   108  	}{
   109  		{"duplicate stack name", CloudResources{
   110  			{
   111  				Kind:       "",
   112  				APIVersion: "",
   113  				Metadata:   Metadata{},
   114  				Spec: v1alpha1.CloudResourceDeploymentSpec{
   115  					Cloudformation: &v1alpha1.StackSpec{
   116  						Parameters: nil,
   117  						Tags:       nil,
   118  						Template:   "",
   119  						Stackname:  "test1",
   120  						CARole:     v1alpha1.AssumeRoleProvider{},
   121  					},
   122  				},
   123  			},
   124  			{
   125  				Kind:       "",
   126  				APIVersion: "",
   127  				Metadata:   Metadata{},
   128  				Spec: v1alpha1.CloudResourceDeploymentSpec{
   129  					Cloudformation: &v1alpha1.StackSpec{
   130  						Parameters: nil,
   131  						Tags:       nil,
   132  						Template:   "",
   133  						Stackname:  "test1",
   134  						CARole:     v1alpha1.AssumeRoleProvider{},
   135  					},
   136  				},
   137  			},
   138  		}, true},
   139  		{"happy path", CloudResources{
   140  			{
   141  				Kind:       "",
   142  				APIVersion: "",
   143  				Metadata:   Metadata{},
   144  				Spec: v1alpha1.CloudResourceDeploymentSpec{
   145  					Cloudformation: &v1alpha1.StackSpec{
   146  						Parameters: nil,
   147  						Tags:       nil,
   148  						Template:   "",
   149  						Stackname:  "test1",
   150  						CARole:     v1alpha1.AssumeRoleProvider{},
   151  					},
   152  				},
   153  			},
   154  			{
   155  				Kind:       "",
   156  				APIVersion: "",
   157  				Metadata:   Metadata{},
   158  				Spec: v1alpha1.CloudResourceDeploymentSpec{
   159  					Cloudformation: &v1alpha1.StackSpec{
   160  						Parameters: nil,
   161  						Tags:       nil,
   162  						Template:   "",
   163  						Stackname:  "test2",
   164  						CARole:     v1alpha1.AssumeRoleProvider{},
   165  					},
   166  				},
   167  			},
   168  		}, true},
   169  	}
   170  
   171  	for _, tt := range table {
   172  		t.Run(tt.name, func(t *testing.T) {
   173  			if err := tt.resources.Validate(); err != nil && !tt.error {
   174  				t.Error(err)
   175  			}
   176  		})
   177  	}
   178  }
   179  
   180  func Test_CloudResourcesRender(t *testing.T) {
   181  	var table = []struct {
   182  		name       string
   183  		resources  CloudResources
   184  		jsonLength int
   185  		yamlLength int
   186  		error      bool
   187  	}{
   188  		{"happy path", CloudResources{
   189  			{
   190  				Kind:       "",
   191  				APIVersion: "",
   192  				Metadata:   Metadata{},
   193  				Spec: v1alpha1.CloudResourceDeploymentSpec{
   194  					Cloudformation: &v1alpha1.StackSpec{
   195  						Parameters: nil,
   196  						Tags:       nil,
   197  						Template:   "",
   198  						Stackname:  "test1",
   199  						CARole: v1alpha1.AssumeRoleProvider{
   200  							RoleARN:         "arn:aws:iam::123456789000:role/cfn-fa-role",
   201  							RoleSessionName: "gitops-deployment",
   202  						},
   203  					},
   204  				},
   205  			},
   206  			{
   207  				Kind:       "",
   208  				APIVersion: "",
   209  				Metadata:   Metadata{},
   210  				Spec: v1alpha1.CloudResourceDeploymentSpec{
   211  					Cloudformation: &v1alpha1.StackSpec{
   212  						Parameters: nil,
   213  						Tags:       nil,
   214  						Template:   "",
   215  						Stackname:  "test2",
   216  						CARole: v1alpha1.AssumeRoleProvider{
   217  							RoleARN:         "arn:aws:iam::123456789000:role/cfn-fa-role",
   218  							RoleSessionName: "gitops-deployment",
   219  						},
   220  					},
   221  				},
   222  			},
   223  		}, 446, 522, true},
   224  	}
   225  
   226  	for _, tt := range table {
   227  		t.Run(tt.name, func(t *testing.T) {
   228  			bytes, err := tt.resources.Render("yaml")
   229  			if err != nil && !tt.error {
   230  				t.Error(err)
   231  			}
   232  
   233  			// TODO: Should validate contents of the yaml doc, not just length
   234  			if len(bytes) != tt.yamlLength {
   235  				t.Logf(string(bytes))
   236  				t.Errorf("YAML byte array length is incorrect; got: %d want %d", len(bytes), tt.yamlLength)
   237  			}
   238  
   239  			bytes, err = tt.resources.Render("json")
   240  			if err != nil && !tt.error {
   241  				t.Error(err)
   242  			}
   243  
   244  			// TODO: Should validate contents of the json doc, not just length
   245  			if len(bytes) != tt.jsonLength {
   246  				t.Logf(string(bytes))
   247  				t.Errorf("JSON byte array length is incorrect; got: %d want %d", len(bytes), tt.jsonLength)
   248  			}
   249  		})
   250  	}
   251  }
   252  
   253  func initTestLogger() (*zap.Logger, error) {
   254  	cfg := zap.Config{
   255  		Encoding:         "console",
   256  		OutputPaths:      []string{"stderr"},
   257  		ErrorOutputPaths: []string{"stderr"},
   258  		Level:            zap.NewAtomicLevelAt(zapcore.DebugLevel),
   259  		EncoderConfig: zapcore.EncoderConfig{
   260  			MessageKey: "message",
   261  
   262  			LevelKey:    "level",
   263  			EncodeLevel: zapcore.CapitalLevelEncoder,
   264  
   265  			TimeKey:    "time",
   266  			EncodeTime: zapcore.ISO8601TimeEncoder,
   267  
   268  			CallerKey:    "caller",
   269  			EncodeCaller: zapcore.ShortCallerEncoder,
   270  		},
   271  	}
   272  
   273  	return cfg.Build()
   274  }