Пример #1
0
        public void RenameFunction()
        {
            // ARRANGE
            var mockFileManager     = GetMockFileManager(string.Empty);
            var lambdaFunctionModel = GetLambdaFunctionModel("MyAssembly::MyNamespace.MyType::Handler",
                                                             "OldName", 45, 512, "@Basic", null);
            var cloudFormationJsonWriter = new CloudFormationJsonWriter(mockFileManager, _mockDirectoryManager, _jsonWriter, _diagnosticReporter);
            var report = GetAnnotationReport(new List <ILambdaFunctionSerializable> {
                lambdaFunctionModel
            });

            // ACT
            cloudFormationJsonWriter.ApplyReport(report);

            // ASSERT
            var rootToken = JObject.Parse(mockFileManager.ReadAllText(ServerlessTemplateFilePath));

            Assert.NotNull(rootToken["Resources"]["OldName"]);
            Assert.Equal("MyAssembly::MyNamespace.MyType::Handler",
                         rootToken["Resources"]["OldName"]["Properties"]["Handler"]);

            // ACT - CHANGE NAME
            lambdaFunctionModel.Name = "NewName";
            cloudFormationJsonWriter.ApplyReport(report);

            // ASSERT
            rootToken = JObject.Parse(mockFileManager.ReadAllText(ServerlessTemplateFilePath));
            Assert.Null(rootToken["Resources"]["OldName"]);
            Assert.NotNull(rootToken["Resources"]["NewName"]);
            Assert.Equal("MyAssembly::MyNamespace.MyType::Handler",
                         rootToken["Resources"]["NewName"]["Properties"]["Handler"]);
        }
Пример #2
0
        public void RemoveOrphanedLambdaFunctions()
        {
            // ARRANGE
            var originalContent     = @"{
                              'AWSTemplateFormatVersion': '2010-09-09',
                              'Transform': 'AWS::Serverless-2016-10-31',
                              'Resources': {
                                'ObsoleteMethod': {
                                  'Type': 'AWS::Serverless::Function',
                                  'Metadata': {
                                    'Tool': 'Amazon.Lambda.Annotations'
                                  },
                                  'Properties': {
                                    'Runtime': 'dotnetcore3.1',
                                    'CodeUri': '',
                                    'MemorySize': 128,
                                    'Timeout': 100,
                                    'Policies': [
                                      'AWSLambdaBasicExecutionRole'
                                    ],
                                    'Handler': 'MyAssembly::MyNamespace.MyType::Handler'
                                  }
                                },
                                'MethodNotCreatedFromAnnotationsPackage': {
                                  'Type': 'AWS::Serverless::Function',
                                  'Properties': {
                                    'Runtime': 'dotnetcore3.1',
                                    'CodeUri': '',
                                    'MemorySize': 128,
                                    'Timeout': 100,
                                    'Policies': [
                                      'AWSLambdaBasicExecutionRole'
                                    ],
                                    'Handler': 'MyAssembly::MyNamespace.MyType::Handler'
                                  }
                                }
                              }
                            }";
            var mockFileManager     = GetMockFileManager(originalContent);
            var lambdaFunctionModel = GetLambdaFunctionModel("MyAssembly::MyNamespace.MyType::Handler",
                                                             "NewMethod", 45, 512, null, null);
            var cloudFormationJsonWriter = new CloudFormationJsonWriter(mockFileManager, _mockDirectoryManager, _jsonWriter, _diagnosticReporter);
            var report = GetAnnotationReport(new List <ILambdaFunctionSerializable> {
                lambdaFunctionModel
            });

            // ACT
            cloudFormationJsonWriter.ApplyReport(report);

            // ASSERT
            var rootToken = JObject.Parse(mockFileManager.ReadAllText(ServerlessTemplateFilePath));

            Assert.Null(rootToken["Resources"]["ObsoleteMethod"]);
            Assert.NotNull(rootToken["Resources"]["NewMethod"]);
            Assert.NotNull(rootToken["Resources"]["MethodNotCreatedFromAnnotationsPackage"]);
        }
Пример #3
0
        public void SwitchFromPolicyToRole()
        {
            // ARRANGE
            var mockFileManager          = GetMockFileManager(string.Empty);
            var cloudFormationJsonWriter = new CloudFormationJsonWriter(mockFileManager, _mockDirectoryManager, _jsonWriter, _diagnosticReporter);

            //ACT - USE POLICY
            var lambdaFunctionModel = GetLambdaFunctionModel("MyAssembly::MyNamespace.MyType::Handler",
                                                             "TestMethod", 45, 512, null, "Policy1, Policy2, Policy3");
            var report = GetAnnotationReport(new List <ILambdaFunctionSerializable> {
                lambdaFunctionModel
            });

            cloudFormationJsonWriter.ApplyReport(report);

            // ASSERT
            var rootToken   = JObject.Parse(mockFileManager.ReadAllText(ServerlessTemplateFilePath));
            var policyArray = rootToken["Resources"]["TestMethod"]["Properties"]["Policies"];

            Assert.Equal(new List <string> {
                "Policy1", "Policy2", "Policy3"
            }, policyArray.ToObject <List <string> >());
            Assert.Null(rootToken["Resources"]["TestMethod"]["Properties"]["Role"]);

            // ACT - SWITCH TO ROLE
            lambdaFunctionModel = GetLambdaFunctionModel("MyAssembly::MyNamespace.MyType::Handler",
                                                         "TestMethod", 45, 512, "Basic", null);
            report = GetAnnotationReport(new List <ILambdaFunctionSerializable> {
                lambdaFunctionModel
            });
            cloudFormationJsonWriter.ApplyReport(report);

            // ASSERT
            rootToken = JObject.Parse(mockFileManager.ReadAllText(ServerlessTemplateFilePath));
            Assert.Equal("Basic", rootToken["Resources"]["TestMethod"]["Properties"]["Role"]);
            Assert.Null(rootToken["Resources"]["TestMethod"]["Properties"]["Policies"]);

            // ACT - SWITCH BACK TO POLICY
            lambdaFunctionModel = GetLambdaFunctionModel("MyAssembly::MyNamespace.MyType::Handler",
                                                         "TestMethod", 45, 512, null, "Policy1, Policy2, Policy3");
            report = GetAnnotationReport(new List <ILambdaFunctionSerializable> {
                lambdaFunctionModel
            });
            cloudFormationJsonWriter.ApplyReport(report);

            // ASSERT
            rootToken   = JObject.Parse(mockFileManager.ReadAllText(ServerlessTemplateFilePath));
            policyArray = rootToken["Resources"]["TestMethod"]["Properties"]["Policies"];
            Assert.Equal(new List <string> {
                "Policy1", "Policy2", "Policy3"
            }, policyArray.ToObject <List <string> >());
            Assert.Null(rootToken["Resources"]["TestMethod"]["Properties"]["Role"]);
        }
Пример #4
0
        public void DoNotModifyFunctionWithoutRequiredMetadata()
        {
            // ARRANGE
            var originalContent = @"{
                              'AWSTemplateFormatVersion': '2010-09-09',
                              'Transform': 'AWS::Serverless-2016-10-31',
                              'Resources': {
                                'MethodNotCreatedFromAnnotationsPackage': {
                                  'Type': 'AWS::Serverless::Function',
                                  'Properties': {
                                    'Runtime': 'dotnetcore3.1',
                                    'CodeUri': '',
                                    'MemorySize': 128,
                                    'Timeout': 100,
                                    'Policies': [
                                      'AWSLambdaBasicExecutionRole'
                                    ],
                                    'Handler': 'MyAssembly::MyNamespace.MyType::Handler'
                                  }
                                }
                              }
                            }";

            var mockFileManager     = GetMockFileManager(originalContent);
            var lambdaFunctionModel = GetLambdaFunctionModel("MyAssembly::MyNamespace.MyType::Handler",
                                                             "MethodNotCreatedFromAnnotationsPackage", 45, 512, null, "Policy1, Policy2, Policy3");
            var cloudFormationJsonWriter = new CloudFormationJsonWriter(mockFileManager, _mockDirectoryManager, _jsonWriter, _diagnosticReporter);
            var report = GetAnnotationReport(new() { lambdaFunctionModel });

            // ACT
            cloudFormationJsonWriter.ApplyReport(report);

            // ASSERT
            var rootToken = JObject.Parse(mockFileManager.ReadAllText(ServerlessTemplateFilePath));

            Assert.NotNull(rootToken["Resources"]["MethodNotCreatedFromAnnotationsPackage"]);
            Assert.Equal(128, rootToken["Resources"]["MethodNotCreatedFromAnnotationsPackage"]["Properties"]["MemorySize"]); // unchanged
            Assert.Equal(100, rootToken["Resources"]["MethodNotCreatedFromAnnotationsPackage"]["Properties"]["Timeout"]);    // unchanged

            var policies = rootToken["Resources"]["MethodNotCreatedFromAnnotationsPackage"]["Properties"]["Policies"] as JArray;

            Assert.NotNull(policies);
            Assert.Single(policies);
            Assert.Equal("AWSLambdaBasicExecutionRole", policies[0]); // unchanged
        }
Пример #5
0
        public void UseRefForPolicies()
        {
            // ARRANGE
            var mockFileManager     = GetMockFileManager(string.Empty);
            var lambdaFunctionModel = GetLambdaFunctionModel("MyAssembly::MyNamespace.MyType::Handler",
                                                             "TestMethod", 45, 512, null, "Policy1, @Policy2, Policy3");
            var cloudFormationJsonWriter = new CloudFormationJsonWriter(mockFileManager, _mockDirectoryManager, _jsonWriter, _diagnosticReporter);
            var report = GetAnnotationReport(new List <ILambdaFunctionSerializable> {
                lambdaFunctionModel
            });

            // ACT
            cloudFormationJsonWriter.ApplyReport(report);

            // ASSERT
            var rootToken = JObject.Parse(mockFileManager.ReadAllText(ServerlessTemplateFilePath));
            var policies  = rootToken["Resources"]["TestMethod"]["Properties"]["Policies"] as JArray;

            Assert.Equal(3, policies.Count);
            Assert.Equal("Policy1", policies[0]);
            Assert.Equal("Policy2", policies[1]["Ref"]);
            Assert.Equal("Policy3", policies[2]);
        }
Пример #6
0
        public void AddSingletonFunctionToEmptyTemplate()
        {
            // ARRANGE
            var mockFileManager     = GetMockFileManager(string.Empty);
            var lambdaFunctionModel = GetLambdaFunctionModel("MyAssembly::MyNamespace.MyType::Handler",
                                                             "TestMethod", 45, 512, null, null);
            var cloudFormationJsonWriter = new CloudFormationJsonWriter(mockFileManager, _mockDirectoryManager, _jsonWriter, _diagnosticReporter);
            var report = GetAnnotationReport(new List <ILambdaFunctionSerializable>()
            {
                lambdaFunctionModel
            });

            // ACT
            cloudFormationJsonWriter.ApplyReport(report);

            // ASSERT
            var rootToken       = JObject.Parse(mockFileManager.ReadAllText(ServerlessTemplateFilePath));
            var functionToken   = rootToken["Resources"]["TestMethod"];
            var propertiesToken = functionToken["Properties"];

            Assert.Equal("2010-09-09", rootToken["AWSTemplateFormatVersion"]);
            Assert.Equal("AWS::Serverless-2016-10-31", rootToken["Transform"]);

            Assert.Equal("AWS::Serverless::Function", functionToken["Type"]);
            Assert.Equal("Amazon.Lambda.Annotations", functionToken["Metadata"]["Tool"]);

            Assert.Equal("MyAssembly::MyNamespace.MyType::Handler", propertiesToken["Handler"]);
            Assert.Equal(512, propertiesToken["MemorySize"]);
            Assert.Equal(45, propertiesToken["Timeout"]);
            Assert.Equal(new List <string> {
                "AWSLambdaBasicExecutionRole"
            }, propertiesToken["Policies"].ToObject <List <string> >());
            Assert.Equal("Zip", propertiesToken["PackageType"]);
            Assert.Equal(".", propertiesToken["CodeUri"]);
            Assert.Null(propertiesToken["ImageUri"]);
            Assert.Null(propertiesToken["ImageConfig"]);
        }
Пример #7
0
        public void Execute(GeneratorExecutionContext context)
        {
            var diagnosticReporter = new DiagnosticReporter(context);

            try
            {
                // retrieve the populated receiver
                if (!(context.SyntaxContextReceiver is SyntaxReceiver receiver))
                {
                    return;
                }

                // If no project directory was detected then skip the generator.
                // This is most likely to happen when the project is empty and doesn't have any classes in it yet.
                if (string.IsNullOrEmpty(receiver.ProjectDirectory))
                {
                    return;
                }

                var semanticModelProvider = new SemanticModelProvider(context);
                if (receiver.StartupClasses.Count > 1)
                {
                    foreach (var startup in receiver.StartupClasses)
                    {
                        // If there are more than one startup class, report them as errors
                        diagnosticReporter.Report(Diagnostic.Create(DiagnosticDescriptors.MultipleStartupNotAllowed,
                                                                    Location.Create(startup.SyntaxTree, startup.Span),
                                                                    startup.SyntaxTree.FilePath));
                    }
                }

                var configureMethodModel = semanticModelProvider.GetConfigureMethodModel(receiver.StartupClasses.FirstOrDefault());

                var annotationReport = new AnnotationReport();

                var templateFinder = new CloudFormationTemplateFinder(_fileManager, _directoryManager);

                foreach (var lambdaMethod in receiver.LambdaMethods)
                {
                    var lambdaMethodModel = semanticModelProvider.GetMethodSemanticModel(lambdaMethod);

                    // Check for necessary references
                    if (lambdaMethodModel.HasAttribute(context, TypeFullNames.RestApiAttribute) ||
                        lambdaMethodModel.HasAttribute(context, TypeFullNames.HttpApiAttribute))
                    {
                        // Check for arbitrary type from "Amazon.Lambda.APIGatewayEvents"
                        if (context.Compilation.ReferencedAssemblyNames.FirstOrDefault(x => x.Name == "Amazon.Lambda.APIGatewayEvents") == null)
                        {
                            diagnosticReporter.Report(Diagnostic.Create(DiagnosticDescriptors.MissingDependencies,
                                                                        lambdaMethod.GetLocation(),
                                                                        "Amazon.Lambda.APIGatewayEvents"));
                        }
                    }

                    var model = LambdaFunctionModelBuilder.Build(lambdaMethodModel, configureMethodModel, context);

                    // If there are more than one event, report them as errors
                    if (model.LambdaMethod.Events.Count > 1)
                    {
                        foreach (var attribute in lambdaMethodModel.GetAttributes().Where(attribute => TypeFullNames.Events.Contains(attribute.AttributeClass.ToDisplayString())))
                        {
                            diagnosticReporter.Report(Diagnostic.Create(DiagnosticDescriptors.MultipleEventsNotSupported,
                                                                        Location.Create(attribute.ApplicationSyntaxReference.SyntaxTree, attribute.ApplicationSyntaxReference.Span),
                                                                        DiagnosticSeverity.Error));
                        }

                        // Skip multi-event lambda method from processing and check remaining lambda methods for diagnostics
                        continue;
                    }

                    var template   = new LambdaFunctionTemplate(model);
                    var sourceText = template.TransformText().ToEnvironmentLineEndings();
                    context.AddSource($"{model.GeneratedMethod.ContainingType.Name}.g.cs", SourceText.From(sourceText, Encoding.UTF8, SourceHashAlgorithm.Sha256));

                    // report every generated file to build output
                    diagnosticReporter.Report(Diagnostic.Create(DiagnosticDescriptors.CodeGeneration, Location.None, $"{model.GeneratedMethod.ContainingType.Name}.g.cs", sourceText));

                    annotationReport.LambdaFunctions.Add(model);
                }

                // Run the CloudFormation sync if any LambdaMethods exists. Also run if no LambdaMethods exists but there is a
                // CloudFormation template in case orphaned functions in the template need to be removed.
                // Both checks are required because if there is no template but there are LambdaMethods the CF template the template will be created.
                if (receiver.LambdaMethods.Any() || templateFinder.DoesCloudFormationTemplateExist(receiver.ProjectDirectory))
                {
                    annotationReport.CloudFormationTemplatePath = templateFinder.FindCloudFormationTemplate(receiver.ProjectDirectory);
                    annotationReport.ProjectRootDirectory       = receiver.ProjectDirectory;
                    var cloudFormationJsonWriter = new CloudFormationJsonWriter(_fileManager, _directoryManager, _jsonWriter, diagnosticReporter);
                    cloudFormationJsonWriter.ApplyReport(annotationReport);
                }
            }
            catch (Exception e)
            {
                // this is a generator failure, report this as error
                diagnosticReporter.Report(Diagnostic.Create(DiagnosticDescriptors.UnhandledException, Location.None, e.PrettyPrint()));
#if DEBUG
                throw;
#endif
            }
        }
Пример #8
0
        public void PackageTypePropertyTest()
        {
            // ARRANGE - Set PackageType to Zip
            var mockFileManager     = GetMockFileManager(string.Empty);
            var lambdaFunctionModel = GetLambdaFunctionModel("MyAssembly::MyNamespace.MyType::Handler",
                                                             "TestMethod", 45, 512, null, null);

            lambdaFunctionModel.PackageType = LambdaPackageType.Zip;
            var cloudFormationJsonWriter = new CloudFormationJsonWriter(mockFileManager, _mockDirectoryManager, _jsonWriter, _diagnosticReporter);
            var report = GetAnnotationReport(new List <ILambdaFunctionSerializable>()
            {
                lambdaFunctionModel
            });

            // ACT
            cloudFormationJsonWriter.ApplyReport(report);

            // ASSERT
            var rootToken       = JObject.Parse(mockFileManager.ReadAllText(ServerlessTemplateFilePath));
            var propertiesToken = rootToken["Resources"]["TestMethod"]["Properties"];

            Assert.Equal("Zip", propertiesToken["PackageType"]);
            Assert.Equal(".", propertiesToken["CodeUri"]);
            Assert.Equal("MyAssembly::MyNamespace.MyType::Handler", propertiesToken["Handler"]);

            // ARRANGE - Change PackageType to Image
            lambdaFunctionModel.PackageType = LambdaPackageType.Image;
            report = GetAnnotationReport(new List <ILambdaFunctionSerializable>()
            {
                lambdaFunctionModel
            });

            // ACT
            cloudFormationJsonWriter.ApplyReport(report);

            // ASSERT
            rootToken       = JObject.Parse(mockFileManager.ReadAllText(ServerlessTemplateFilePath));
            propertiesToken = rootToken["Resources"]["TestMethod"]["Properties"];
            Assert.Equal("Image", propertiesToken["PackageType"]);
            Assert.Equal(".", propertiesToken["ImageUri"]);
            Assert.Equal(new JArray("MyAssembly::MyNamespace.MyType::Handler"), propertiesToken["ImageConfig"]["Command"]);
            Assert.Null(propertiesToken["CodeUri"]);
            Assert.Null(propertiesToken["Handler"]);

            // ARRANGE - Change PackageType back to Zip
            lambdaFunctionModel.PackageType = LambdaPackageType.Zip;
            report = GetAnnotationReport(new List <ILambdaFunctionSerializable>()
            {
                lambdaFunctionModel
            });

            // ACT
            cloudFormationJsonWriter.ApplyReport(report);

            // ASSERT
            rootToken       = JObject.Parse(mockFileManager.ReadAllText(ServerlessTemplateFilePath));
            propertiesToken = rootToken["Resources"]["TestMethod"]["Properties"];
            Assert.Equal("Zip", propertiesToken["PackageType"]);
            Assert.Equal(".", propertiesToken["CodeUri"]);
            Assert.Equal("MyAssembly::MyNamespace.MyType::Handler", propertiesToken["Handler"]);
            Assert.Null(propertiesToken["ImageUri"]);
            Assert.Null(propertiesToken["ImageConfig"]);
        }
Пример #9
0
        public void EventAttributesTest()
        {
            // ARRANGE - USE A HTTP GET METHOD
            var mockFileManager     = GetMockFileManager(string.Empty);
            var lambdaFunctionModel = GetLambdaFunctionModel("MyAssembly::MyNamespace.MyType::Handler",
                                                             "TestMethod", 45, 512, null, null);
            var httpAttributeModel = new AttributeModel <HttpApiAttribute>()
            {
                Data = new HttpApiAttribute(LambdaHttpMethod.Get, "/Calculator/Add")
                {
                    Version = HttpApiVersion.V1
                }
            };

            lambdaFunctionModel.Attributes = new List <AttributeModel>()
            {
                httpAttributeModel
            };
            var cloudFormationJsonWriter = new CloudFormationJsonWriter(mockFileManager, _mockDirectoryManager, _jsonWriter, _diagnosticReporter);
            var report = GetAnnotationReport(new List <ILambdaFunctionSerializable>()
            {
                lambdaFunctionModel
            });

            // ACT
            cloudFormationJsonWriter.ApplyReport(report);

            // ASSERT
            var rootToken = JObject.Parse(mockFileManager.ReadAllText(ServerlessTemplateFilePath));
            var getToken  = rootToken["Resources"]["TestMethod"]["Properties"]["Events"]["RootGet"];

            Assert.NotNull(getToken);
            Assert.Equal("HttpApi", getToken["Type"]);
            Assert.Equal("/Calculator/Add", getToken["Properties"]["Path"]);
            Assert.Equal("GET", getToken["Properties"]["Method"]);
            Assert.Equal("1.0", getToken["Properties"]["PayloadFormatVersion"]);

            // ARRANGE - CHANGE TO A HTTP POST METHOD
            httpAttributeModel = new AttributeModel <HttpApiAttribute>()
            {
                Data = new HttpApiAttribute(LambdaHttpMethod.Post, "/Calculator/Add")
            };
            lambdaFunctionModel.Attributes = new List <AttributeModel>()
            {
                httpAttributeModel
            };

            // ACT
            cloudFormationJsonWriter.ApplyReport(report);

            // ASSERT
            rootToken = JObject.Parse(mockFileManager.ReadAllText(ServerlessTemplateFilePath));
            getToken  = rootToken["Resources"]["TestMethod"]["Properties"]["Events"]["RootGet"];
            var postToken = rootToken["Resources"]["TestMethod"]["Properties"]["Events"]["RootPost"];

            Assert.Null(getToken); // Verify that the HTTP GET method entry is deleted
            Assert.NotNull(postToken);
            Assert.Equal("HttpApi", postToken["Type"]);
            Assert.Equal("/Calculator/Add", postToken["Properties"]["Path"]);
            Assert.Equal("POST", postToken["Properties"]["Method"]);
            Assert.Equal("2.0", postToken["Properties"]["PayloadFormatVersion"]);
        }