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 }