internal async Task ShouldWarnWhenInlineRubyLambdaHasMissingHandlerMethod() { var logger = new TestLogger(this.output); var mockS3 = new Mock <IPSS3Util>(); var lambdaFunctionResource = this.LambdaFunctionResource( "index.mistyped_handler", "ruby2.7", new Dictionary <object, object> { { "ZipFile", InlineRuby } }); var mockOSInfo = new Mock <IOSInfo>(); mockOSInfo.Setup(i => i.OSPlatform).Returns(OSPlatform.Windows); var artifact = new LambdaArtifact( new TestPathResolver(), lambdaFunctionResource, new TestLogger(this.output), mockOSInfo.Object, Directory.GetCurrentDirectory()); var packager = LambdaPackager.CreatePackager(artifact, mockS3.Object, logger, new OSInfo()); Func <Task> act = async() => { await packager.Package(null); }; await act.Should().NotThrowAsync(); logger.WarningMessages.Should().ContainMatch( "*If your method is within a class, validation is not yet supported for this."); }
internal async Task ShouldThrowWhenInlineLambdaHasMissingHandlerMethod(string resourceType, string runtime) { var mockS3 = new Mock <IPSS3Util>(); var mockLambdaFunctionResource = new Mock <IResource>(); mockLambdaFunctionResource.Setup(r => r.Name).Returns("MockInlineLambda"); mockLambdaFunctionResource.Setup(r => r.Type).Returns(resourceType); mockLambdaFunctionResource.Setup(r => r.GetResourcePropertyValue("Runtime")).Returns(runtime); mockLambdaFunctionResource.Setup(r => r.GetResourcePropertyValue("Handler")) .Returns("index.mistyped_handler"); mockLambdaFunctionResource.Setup(r => r.GetResourcePropertyValue(InlineCodePropertyMap[resourceType])) .Returns(InlineCodeCodeMap[runtime]); var mockOSInfo = new Mock <IOSInfo>(); mockOSInfo.Setup(i => i.OSPlatform).Returns(OSPlatform.Windows); var artifact = new LambdaArtifact( new TestPathResolver(), mockLambdaFunctionResource.Object, new TestLogger(this.output), mockOSInfo.Object, Directory.GetCurrentDirectory()); // Verify parsing var packager = LambdaPackager.CreatePackager(artifact, mockS3.Object, new TestLogger(this.output), new OSInfo()); artifact.HandlerInfo.MethodPart.Should().Be("mistyped_handler"); Func <Task> act = async() => { await packager.Package(null); }; await act.Should().ThrowAsync <PackagerException>().WithMessage("*Cannot locate handler method*"); }
public async Task ShouldValidateHandlerForPreZippedLambda() { var mockS3 = new Mock <IPSS3Util>(); var template = Path.Combine(this.handlerTestDirectory, "zipped_lambda.yaml"); var parser = TemplateParser.Create(await File.ReadAllTextAsync(template)); var function = parser.GetResources().FirstOrDefault(r => r.Type == "AWS::Serverless::Function"); function.Should().NotBeNull("you broke the template!"); var mockOSInfo = new Mock <IOSInfo>(); mockOSInfo.Setup(i => i.OSPlatform).Returns(OSPlatform.Windows); var artifact = new LambdaArtifact(new TestPathResolver(), function, new TestLogger(this.output), mockOSInfo.Object, template); var packager = LambdaPackager.CreatePackager(artifact, mockS3.Object, new TestLogger(this.output), new OSInfo()); Func <Task> act = async() => { await packager.Package(null); }; await act.Should().NotThrowAsync(); }
internal async Task ShouldParseAndValidateInlineLambdaFunction( string resourceType, LambdaRuntimeType expectedRuntimeType, string runtime) { var mockS3 = new Mock <IPSS3Util>(); var mockLambdaFunctionResource = new Mock <IResource>(); mockLambdaFunctionResource.Setup(r => r.Name).Returns("MockInlineLambda"); mockLambdaFunctionResource.Setup(r => r.Type).Returns(resourceType); mockLambdaFunctionResource.Setup(r => r.GetResourcePropertyValue("Runtime")).Returns(runtime); mockLambdaFunctionResource.Setup(r => r.GetResourcePropertyValue("Handler")).Returns("index.handler"); mockLambdaFunctionResource.Setup(r => r.GetResourcePropertyValue(InlineCodePropertyMap[resourceType])) .Returns(InlineCodeCodeMap[runtime]); var mockOSInfo = new Mock <IOSInfo>(); mockOSInfo.Setup(i => i.OSPlatform).Returns(OSPlatform.Windows); var artifact = new LambdaArtifact( new TestPathResolver(), mockLambdaFunctionResource.Object, new TestLogger(this.output), mockOSInfo.Object, Directory.GetCurrentDirectory()); // Verify parsing artifact.ArtifactType.Should().Be(LambdaArtifactType.Inline); artifact.InlineCode.Should().NotBeNull(); artifact.RuntimeInfo.RuntimeType.Should().Be(expectedRuntimeType); artifact.HandlerInfo.FilePart.Should().Be("index"); artifact.HandlerInfo.MethodPart.Should().Be("handler"); // Verify handler check var packager = LambdaPackager.CreatePackager(artifact, mockS3.Object, new TestLogger(this.output), new OSInfo()); Func <Task> act = async() => { await packager.Package(null); }; await act.Should().NotThrowAsync(); }
/// <summary> /// Processes resources that can point to artifacts in S3. /// </summary> /// <param name="resource">The resource.</param> /// <param name="templatePath">The template path.</param> /// <param name="workingDirectory">The working directory.</param> /// <returns><c>true</c> if the containing template should be modified (to point to S3); else <c>false</c></returns> /// <exception cref="InvalidDataException">Unsupported derivative of FileSystemInfo</exception> /// <exception cref="MissingMethodException">Missing constructor for the replacement template artifact.</exception> private async Task <bool> ProcessResource( IResource resource, string templatePath, string workingDirectory) { var templateModified = false; foreach (var propertyToCheck in PackagedResources[resource.Type]) { ResourceUploadSettings resourceToUpload; // See if we have a lambda var lambdaResource = new LambdaArtifact(this.pathResolver, resource, this.logger, this.platform, templatePath); if (lambdaResource.ArtifactType != LambdaArtifactType.NotLambda) { // We do using (var packager = LambdaPackager.CreatePackager(lambdaResource, this.s3Util, this.logger, this.platform)) { resourceToUpload = await packager.Package(workingDirectory); if (resourceToUpload == null) { // Lambda syntax does not imply a template modification // i.e. it is inline code or already an S3 reference. continue; } // The template will be altered to an S3 location, // however the zip may or may not be uploaded. templateModified = true; } } else { string resourceFile; try { resourceFile = (string)resource.GetResourcePropertyValue(propertyToCheck.PropertyPath); } catch (FormatException) { if (!propertyToCheck.Required) { // Property is missing, but CloudFormation does not require it. continue; } throw; } if (resourceFile == null) { // Property was not found, or was not a value type. continue; } var fsi = ResolveFileSystemResource(this.pathResolver, templatePath, resourceFile); if (fsi == null) { // Property value did not resolve to a path in the file system continue; } templateModified = true; switch (fsi) { case FileInfo fi: // Property value points to a file resourceToUpload = await ArtifactPackager.PackageFile( fi, workingDirectory, propertyToCheck.Zip, this.s3Util, this.logger); break; case DirectoryInfo di: // Property value points to a directory, which must always be zipped. resourceToUpload = await ArtifactPackager.PackageDirectory( di, workingDirectory, this.s3Util, this.logger); break; default: // Should never get here, but shuts up a bunch of compiler/R# warnings throw new InvalidDataException( $"Unsupported derivative of FileSystemInfo: {fsi.GetType().FullName}"); } } if (!resourceToUpload.HashMatch) { resourceToUpload.KeyPrefix = this.s3Util.KeyPrefix; resourceToUpload.Metadata = this.s3Util.Metadata; await this.s3Util.UploadResourceToS3Async(resourceToUpload); } if (propertyToCheck.ReplacementType == typeof(string)) { // Insert the URI directly resource.UpdateResourceProperty(propertyToCheck.PropertyPath, resourceToUpload.S3Artifact.Url); } else { // Create an instance of the new mapping // ReSharper disable once StyleCop.SA1305 var s3Location = propertyToCheck.ReplacementType.GetConstructor(new[] { typeof(S3Artifact) }) ?.Invoke(new object[] { resourceToUpload.S3Artifact }); if (s3Location == null) { throw new MissingMethodException(propertyToCheck.ReplacementType.FullName, ".ctor(S3Artifact)"); } // and set on the resource property resource.UpdateResourceProperty(propertyToCheck.PropertyPath, s3Location); } } return(templateModified); }