Skip to content

Commit

Permalink
ci: Add integration tests for local invoke related to AWS credentials (
Browse files Browse the repository at this point in the history
…#2449)

* ci: add integration tests for local invoke which uses credentials

* ci: add nodejs, dotnet, golang projects. removed env vars for process

* chore: update build command verification

Co-authored-by: mgrandis <[email protected]>
  • Loading branch information
mndeveci and mgrandis authored Dec 11, 2020
1 parent 08193e7 commit c1b05ce
Show file tree
Hide file tree
Showing 15 changed files with 389 additions and 0 deletions.
35 changes: 35 additions & 0 deletions tests/integration/local/invoke/invoke_integ_base.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import os
from unittest import TestCase, skipIf
from pathlib import Path
from subprocess import Popen, PIPE, TimeoutExpired

from tests.testing_utils import SKIP_DOCKER_MESSAGE, SKIP_DOCKER_TESTS

TIMEOUT = 300


@skipIf(SKIP_DOCKER_TESTS, SKIP_DOCKER_MESSAGE)
class InvokeIntegBase(TestCase):
Expand Down Expand Up @@ -75,3 +78,35 @@ def get_command_list(
command_list = command_list + ["--region", region]

return command_list

def get_build_command_list(
self,
template_path=None,
cached=None,
parallel=None,
use_container=None,
):
command_list = [self.cmd, "build"]

if template_path:
command_list = command_list + ["-t", template_path]

if cached:
command_list = command_list + ["-c"]

if parallel:
command_list = command_list + ["-p"]

if use_container:
command_list = command_list + ["-u"]

return command_list

def run_command(self, command_list, env=None):
process = Popen(command_list, stdout=PIPE, env=env)
try:
(stdout, stderr) = process.communicate(timeout=TIMEOUT)
return stdout, stderr, process.returncode
except TimeoutExpired:
process.kill()
raise
41 changes: 41 additions & 0 deletions tests/integration/local/invoke/test_with_credentials.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from pathlib import Path
import os

from unittest import skipIf
from parameterized import parameterized

from tests.integration.local.invoke.invoke_integ_base import InvokeIntegBase
from tests.testing_utils import RUNNING_ON_CI, RUN_BY_CANARY

SKIP_CREDENTIALS_TESTS = RUNNING_ON_CI and not RUN_BY_CANARY


@skipIf(SKIP_CREDENTIALS_TESTS, "Run credentials test only in Canary")
class TestWithCredentials(InvokeIntegBase):
template = Path("credential_tests/template.yaml")

@parameterized.expand(
[
"JavaStsExample",
"PythonStsExample",
"RubyStsExample",
"NodeStsExample",
"DotnetStsExample",
"GoStsExample",
]
)
def test_build_and_invoke_functions(self, function_name):
"""
This method will first build functions (which contains a credentials call)
Then invoke each of them with passing AWS session env variables
"""
# first build application
build_command_list = self.get_build_command_list(template_path=self.template_path, cached=True)
stdout, _, returncode = self.run_command(build_command_list)
self.assertEqual(returncode, 0)

# then invoke using temp credentials
local_invoke_command_list = self.get_command_list(function_to_invoke=function_name)
stdout, _, returncode = self.run_command(local_invoke_command_list)
self.assertEqual(returncode, 0)
self.assertTrue(b'"statusCode":200' in stdout)
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Newtonsoft.Json;

using Amazon.Lambda.Core;
using Amazon.Lambda.APIGatewayEvents;
using System;
using Amazon.SecurityToken;
using Amazon.SecurityToken.Model;

// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]

namespace STS
{

public class Function
{

public async Task<APIGatewayProxyResponse> FunctionHandler(APIGatewayProxyRequest apigProxyEvent, ILambdaContext context)
{
var client = new AmazonSecurityTokenServiceClient();
var response = await client.GetCallerIdentityAsync(new GetCallerIdentityRequest {});
string account = response.Account;

var body = new Dictionary<string, string>
{
{ "message", "hello world" },
{"account", account}
};

return new APIGatewayProxyResponse
{
Body = JsonConvert.SerializeObject(body),
StatusCode = 200,
Headers = new Dictionary<string, string> { { "Content-Type", "application/json" } }
};
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Amazon.Lambda.Core" Version="1.1.0" />
<PackageReference Include="AWSSDK.SecurityToken" Version="3.5.0.18" />
<PackageReference Include="Amazon.Lambda.APIGatewayEvents" Version="1.2.0" />
<PackageReference Include="Amazon.Lambda.Serialization.Json" Version="1.5.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
</ItemGroup>

</Project>

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
require (
github.com/aws/aws-lambda-go v1.13.3
github.com/aws/aws-sdk-go v1.34.28
)

module golang

go 1.13
38 changes: 38 additions & 0 deletions tests/integration/testdata/invoke/credential_tests/golang/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package main

import (
"fmt"

"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/sts"
)

func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
svc := sts.New(session.New())
input := &sts.GetCallerIdentityInput{}

result, err := svc.GetCallerIdentity(input)
if err != nil {
if aerr, ok := err.(awserr.Error); ok {
switch aerr.Code() {
default:
fmt.Println(aerr.Error())
}
} else {
fmt.Println(err.Error())
}
}

response := fmt.Sprintf("{\"message\": \"Hello world\", \"account\": \"%v\"}", *result.Account)
return events.APIGatewayProxyResponse{
Body: response,
StatusCode: 200,
}, nil
}

func main() {
lambda.Start(handler)
}
51 changes: 51 additions & 0 deletions tests/integration/testdata/invoke/credential_tests/java8/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>sts</groupId>
<artifactId>STSTest</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<name>A sample STS App created for SAM CLI.</name>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>

<dependencies>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-core</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-events</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-sts</artifactId>
<version>1.11.908</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.1</version>
<configuration>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package sts;

import com.amazonaws.auth.EnvironmentVariableCredentialsProvider;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
import com.amazonaws.services.securitytoken.AWSSecurityTokenService;
import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClientBuilder;
import com.amazonaws.services.securitytoken.model.GetCallerIdentityRequest;
import com.amazonaws.services.securitytoken.model.GetCallerIdentityResult;

import java.util.HashMap;
import java.util.Map;

/**
* Handler for requests to Lambda function.
*/
public class App implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {

public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent input, final Context context) {
AWSSecurityTokenServiceClientBuilder awsSecurityTokenServiceClientBuilder =
AWSSecurityTokenServiceClientBuilder.standard();
awsSecurityTokenServiceClientBuilder.setCredentials(new EnvironmentVariableCredentialsProvider());
AWSSecurityTokenService securityClient = awsSecurityTokenServiceClientBuilder.build();
GetCallerIdentityRequest securityRequest = new GetCallerIdentityRequest();
GetCallerIdentityResult securityResponse = securityClient.getCallerIdentity(securityRequest);

Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/json");
headers.put("X-Custom-Header", "application/json");
APIGatewayProxyResponseEvent response = new APIGatewayProxyResponseEvent()
.withHeaders(headers);

String output = String.format("{ \"message\": \"hello world\", \"account\": \"%s\" }",
securityResponse.getAccount());

return response
.withStatusCode(200)
.withBody(output);
}

}
22 changes: 22 additions & 0 deletions tests/integration/testdata/invoke/credential_tests/nodejs/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
let AWS = require('aws-sdk');
let sts = new AWS.STS();

exports.lambdaHandler = async (event, context) => {
let response;
try {
const sts_response = await sts.getCallerIdentity().promise();

response = {
'statusCode': 200,
'body': JSON.stringify({
message: 'hello world',
account: sts_response.Account
})
}
} catch (err) {
console.log(err);
return err;
}

return response
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "npmdeps",
"version": "1.0.0",
"description": "",
"keywords": [],
"author": "",
"license": "APACHE2.0",
"dependencies": {
"aws-sdk": "2.803.0"
}
}
15 changes: 15 additions & 0 deletions tests/integration/testdata/invoke/credential_tests/python/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import boto3
import json


def lambda_handler(event, context):
client = boto3.client('sts')
response = client.get_caller_identity()

return {
"statusCode": 200,
"body": json.dumps({
"message": "hello world",
"account": response.get('Account')
}),
}
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
source "https://rubygems.org"

ruby '~> 2.7.0'
17 changes: 17 additions & 0 deletions tests/integration/testdata/invoke/credential_tests/ruby/app.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
require 'json'
require 'aws-sdk-core'

def lambda_handler(event:, context:)
begin
client = Aws::STS::Client.new()
resp = client.get_caller_identity({})
end

{
statusCode: 200,
body: {
message: "Hello World!",
account: resp.account
}.to_json
}
end
Loading

0 comments on commit c1b05ce

Please sign in to comment.