Skip to content

Commit

Permalink
Add lambda and improve tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Oleh Halay committed Apr 26, 2023
1 parent 115496a commit 0f6cea3
Show file tree
Hide file tree
Showing 20 changed files with 468 additions and 49 deletions.
147 changes: 147 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
root = true
###############################
# Core EditorConfig Options #
###############################
# All files
[*]
indent_style = space

# Microsoft .NET properties
csharp_new_line_before_members_in_object_initializers = true

# ReSharper properties
resharper_wrap_object_and_collection_initializer_style = chop_always

# XML project files
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
indent_size = 2

# XML config files
[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]
indent_size = 2

# Code files
[*.{cs,csx,vb,vbx}]
dotnet_analyzer_diagnostic.category-Style.severity = warning
indent_size = 4
insert_final_newline = true
charset = utf-8
###############################
# .NET Coding Conventions #
###############################
[*.{cs,vb}]
# Organize usings
dotnet_sort_system_directives_first = true
# this. preferences
dotnet_style_qualification_for_field = false:silent
dotnet_style_qualification_for_property = false:silent
dotnet_style_qualification_for_method = false:silent
dotnet_style_qualification_for_event = false:silent
# Language keywords vs BCL types preferences
dotnet_style_predefined_type_for_locals_parameters_members = true:silent
dotnet_style_predefined_type_for_member_access = true:silent
# Parentheses preferences
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
# Modifier preferences
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
dotnet_style_readonly_field = true:suggestion
# Expression-level preferences
dotnet_style_object_initializer = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_explicit_tuple_names = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent
dotnet_style_prefer_inferred_tuple_names = true:suggestion
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
dotnet_style_prefer_auto_properties = true:silent
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
dotnet_style_prefer_conditional_expression_over_return = true:silent
###############################
# Naming Conventions #
###############################
# Style Definitions
dotnet_naming_style.uppercase_style.capitalization = all_upper
# Use PascalCase for constant fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = uppercase_style
dotnet_naming_symbols.constant_fields.applicable_kinds = field
dotnet_naming_symbols.constant_fields.applicable_accessibilities = *
dotnet_naming_symbols.constant_fields.required_modifiers = const
dotnet_style_operator_placement_when_wrapping = beginning_of_line
tab_width = 4
end_of_line = crlf
dotnet_diagnostic.CA1050.severity = suggestion
dotnet_diagnostic.CA1848.severity = suggestion
###############################
# C# Coding Conventions #
###############################
[*.cs]
# var preferences
csharp_style_var_for_built_in_types = true:silent
csharp_style_var_when_type_is_apparent = true:silent
csharp_style_var_elsewhere = true:silent
# Expression-bodied members
csharp_style_expression_bodied_methods = false:silent
csharp_style_expression_bodied_constructors = false:silent
csharp_style_expression_bodied_operators = false:silent
csharp_style_expression_bodied_properties = true:silent
csharp_style_expression_bodied_indexers = true:silent
csharp_style_expression_bodied_accessors = true:silent
# Pattern matching preferences
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
# Null-checking preferences
csharp_style_throw_expression = true:suggestion
csharp_style_conditional_delegate_call = true:suggestion
# Modifier preferences
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion
# Expression-level preferences
csharp_prefer_braces = true:silent
csharp_style_deconstructed_variable_declaration = true:suggestion
csharp_prefer_simple_default_expression = true:suggestion
csharp_style_prefer_local_over_anonymous_function = true:suggestion
csharp_style_inlined_variable_declaration = true:suggestion
###############################
# C# Formatting Rules #
###############################
# New line preferences
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_between_query_expression_clauses = true
# Indentation preferences
csharp_indent_case_contents = true
csharp_indent_switch_labels = true
csharp_indent_labels = flush_left
# Space preferences
csharp_space_after_cast = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = false
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_around_binary_operators = before_and_after
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
# Wrapping preferences
csharp_preserve_single_line_statements = true
csharp_preserve_single_line_blocks = true
csharp_using_directive_placement = outside_namespace:silent
csharp_prefer_simple_using_statement = true:suggestion
csharp_style_namespace_declarations = block_scoped:silent
csharp_style_prefer_method_group_conversion = true:silent
csharp_style_prefer_top_level_statements = true:silent
dotnet_diagnostic.IDE0021.severity = silent
dotnet_diagnostic.IDE0160.severity = silent
dotnet_diagnostic.IDE0061.severity = silent
dotnet_diagnostic.IDE0022.severity = silent
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -341,4 +341,5 @@ ASALocalRun/

# End of https://www.gitignore.io/api/csharp

codeanalysis.sarif.json
codeanalysis.sarif.json
coverage
10 changes: 10 additions & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Project>
<PropertyGroup>
<AnalysisLevel>latest-Recommended</AnalysisLevel>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
<AnalysisMode>All</AnalysisMode>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
</Project>
37 changes: 0 additions & 37 deletions LocalStack.Test/S3Test.cs

This file was deleted.

1 change: 0 additions & 1 deletion LocalStack.Test/Usings.cs

This file was deleted.

21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[![Build&Test](https://github.com/ohalay/serverless-containers/actions/workflows/ci.yml/badge.svg)](https://github.com/ohalay/serverless-containers/actions/workflows/ci.yml)
![GitHub repo size](https://img.shields.io/github/repo-size/ohalay/serverless-containers)
![GitHub contributors](https://img.shields.io/github/contributors/ohalay/serverless-containers)
![GitHub stars](https://img.shields.io/github/stars/ohalay/serverless-containers?style=social)
![GitHub forks](https://img.shields.io/github/forks/ohalay/serverless-containers?style=social)

# Serverless integration tests
A public feed with available products that updates every day

## Business problem
- Integration tests for serverless solution

## Requirements
* Docker

## Implementation

1. S3 public buckets with available documents
2. Lambda updates document


8 changes: 8 additions & 0 deletions Serverless.Lambda.Test/GlobalSuppressions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.

using System.Diagnostics.CodeAnalysis;

[assembly: SuppressMessage("Design", "CA1051:Do not declare visible instance fields", Justification = "<Pending>", Scope = "member", Target = "~F:Serverless.Lambda.Test.LocalStackFixture.Container")]
30 changes: 30 additions & 0 deletions Serverless.Lambda.Test/LambdaHandlerTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Amazon.Lambda.TestUtilities;
using Amazon.S3;
using FluentAssertions;
using Microsoft.Extensions.DependencyInjection;

namespace Serverless.Lambda.Test;

public class LambdaHandlerTest : IClassFixture<LocalStackFixture>
{
private readonly LocalStackFixture fixture;

public LambdaHandlerTest(LocalStackFixture localStackFixture)
=> fixture = localStackFixture;

[Fact]
public async Task HandleShoudPutDocToS3Test()
{
var client = new AmazonS3Client(new AmazonS3Config { ServiceURL = fixture.Container.GetConnectionString() });

var sut = new LambdaHandler(collection => collection
.AddSingleton<IAmazonS3>(client)
.PostConfigure<Config>(c => c.BucketName = LocalStackFixture.BUCKETNAME));

var docId = Guid.NewGuid().ToString();
await sut.Handle(new TestLambdaContext { AwsRequestId = docId });

var res = await client.GetObjectAsync(LocalStackFixture.BUCKETNAME, $"{docId}.txt");
_ = res.HttpStatusCode.Should().Be(System.Net.HttpStatusCode.OK);
}
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,19 @@
using DotNet.Testcontainers.Builders;
using Testcontainers.LocalStack;

namespace LocalStack.Test;
namespace Serverless.Lambda.Test;

public class LocalStackFixture : IAsyncLifetime
{
public const string BUCKETNAME = "test-bucket";

public readonly LocalStackContainer Container = new LocalStackBuilder()
.WithImage("localstack/localstack:latest")
.WithWaitStrategy(Wait.ForUnixContainer().UntilCommandIsCompleted(new[]
{
"awslocal", "s3api", "create-bucket", "--bucket", BUCKETNAME,
}))
.WithStartupCallback((container, ct) => container.ExecAsync(new[] { "awslocal", "s3api", "create-bucket", "--bucket", BUCKETNAME }, ct))
.Build();

static LocalStackFixture()
{
Environment.SetEnvironmentVariable("AWS_ACCESS_KEY_ID", "my-test-key");
Environment.SetEnvironmentVariable("AWS_SECRET_ACCESS_KEY", "my-test-secret-key");
Environment.SetEnvironmentVariable("AWS_ACCESS_KEY_ID", "dummy");
Environment.SetEnvironmentVariable("AWS_SECRET_ACCESS_KEY", "dummy");
}

public Task DisposeAsync()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Amazon.Lambda.TestUtilities" Version="2.0.0" />
<PackageReference Include="AWSSDK.S3" Version="3.7.104.3" />
<PackageReference Include="FluentAssertions" Version="6.11.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
Expand All @@ -25,4 +26,8 @@
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Serverless.Lambda\Serverless.Lambda.csproj" />
</ItemGroup>

</Project>
1 change: 1 addition & 0 deletions Serverless.Lambda.Test/Usings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
global using Xunit;
4 changes: 4 additions & 0 deletions Serverless.Lambda/Config.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
public class Config
{
public string BucketName { get; set; } = string.Empty;
}
51 changes: 51 additions & 0 deletions Serverless.Lambda/Executor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using System.Text;
using Amazon.Lambda.Core;
using Amazon.S3;
using Amazon.S3.Model;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace Serverless.Lambda;

internal interface IExecutor
{
Task Execute(ILambdaContext ctx);
}

public class Executor : IExecutor
{
private readonly ILogger<Executor> logger;
private readonly IAmazonS3 s3Client;
private readonly Config config;

public Executor(
ILogger<Executor> logger,
IAmazonS3 s3Client,
IOptions<Config> options)
{
this.logger = logger;
this.s3Client = s3Client;
config = options.Value;
}
public async Task Execute(ILambdaContext ctx)
{
var content = "this is my test content";
var stream = new MemoryStream(Encoding.UTF8.GetBytes(content));

await Save(ctx.AwsRequestId, stream);

logger.LogInformation("File saved.");
}

private async Task Save(string key, Stream stream)
{
var request = new PutObjectRequest
{
BucketName = config.BucketName,
InputStream = stream,
Key = $"{key}.txt",
};

_ = await s3Client.PutObjectAsync(request);
}
}

0 comments on commit 0f6cea3

Please sign in to comment.