Esempio n. 1
0
        public void ShouldLoadDependencies(string format)
        {
            var deleteMap = new Dictionary <string, string> {
                { "json", "yaml" }, { "yaml", "json" }
            };

            // dependencyFiles temp dir is initialized each test by ctor,
            // so delete the dependency file NOT being tested
            File.Delete(Path.Combine(this.dependencyFiles, $"lambda-dependencies.{deleteMap[format]}"));

            var lambdaFunctionResource =
                this.LambdaFunctionResource("index.handler", "python3.6", this.dependencyFiles.FullPath);

            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,
                this.dependencyFiles);

            var dependencies = artifact.LoadDependencies();

            dependencies.Count.Should().Be(2);
        }
Esempio n. 2
0
        public void ShouldResolveRelativeDependencies(string format)
        {
            var deleteMap = new Dictionary <string, string> {
                { "json", "yaml" }, { "yaml", "json" }
            };

            // dependencyFiles temp dir is initialized each test by ctor,
            // so delete the dependency file NOT being tested
            File.Delete(Path.Combine(this.dependencyFiles, $"lambda-dependencies.{deleteMap[format]}"));

            var lambdaFunctionResource =
                this.LambdaFunctionResource("index.handler", "nodejs10.x", this.dependencyFiles.FullPath);

            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,
                this.dependencyFiles);

            var dependencyFile         = Path.Combine(this.dependencyFiles, $"lambda-dependencies.{format}");
            var expectedDependencyPath = Path.GetFullPath(Path.Combine(new FileInfo(dependencyFile).DirectoryName, "../modules"));

            // Last entry in the lambda-dependencies files has a relative link
            var relativeDependency = artifact.LoadDependencies().Last();

            relativeDependency.Location.Should().Be(expectedDependencyPath);
        }
Esempio n. 3
0
        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.");
        }
Esempio n. 4
0
        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*");
        }
Esempio n. 5
0
        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();
        }
Esempio n. 6
0
        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);
        }