Skip to content

RUBY-3149 Test FaaS (AWS Lambda) Behavior Per Driver #2792

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .evergreen/aws_lambda
52 changes: 33 additions & 19 deletions .evergreen/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,18 @@ functions:
export SERVERLESS_API_PRIVATE_KEY="${SERVERLESS_API_PRIVATE_KEY}"
export SERVERLESS_ATLAS_USER="${SERVERLESS_ATLAS_USER}"
export SERVERLESS_ATLAS_PASSWORD="${SERVERLESS_ATLAS_PASSWORD}"
export LAMBDA_AWS_ROLE_ARN="${LAMBDA_AWS_ROLE_ARN}"

# For starting/stopping/managing an atlas cluster
export DRIVERS_ATLAS_PUBLIC_API_KEY="${DRIVERS_ATLAS_PUBLIC_API_KEY}"
export DRIVERS_ATLAS_PRIVATE_API_KEY="${DRIVERS_ATLAS_PRIVATE_API_KEY}"
export DRIVERS_ATLAS_GROUP_ID="${DRIVERS_ATLAS_GROUP_ID}"
export DRIVERS_ATLAS_LAMBDA_USER="${DRIVERS_ATLAS_LAMBDA_USER}"
export DRIVERS_ATLAS_LAMBDA_PASSWORD="${DRIVERS_ATLAS_LAMBDA_PASSWORD}"
export LAMBDA_STACK_NAME="dbx-ruby-lambda"
export MONGODB_VERSION="7.0"
export task_id="${task_id}"
export execution="${execution}"

# Needed for generating temporary aws credentials.
if [ -n "${FLE}" ];
Expand Down Expand Up @@ -481,17 +493,7 @@ task_groups:
working_dir: "src"
script: |
${PREPARE_SHELL}

DRIVERS_ATLAS_PUBLIC_API_KEY="${DRIVERS_ATLAS_PUBLIC_API_KEY}" \
DRIVERS_ATLAS_PRIVATE_API_KEY="${DRIVERS_ATLAS_PRIVATE_API_KEY}" \
DRIVERS_ATLAS_GROUP_ID="${DRIVERS_ATLAS_GROUP_ID}" \
DRIVERS_ATLAS_LAMBDA_USER="${DRIVERS_ATLAS_LAMBDA_USER}" \
DRIVERS_ATLAS_LAMBDA_PASSWORD="${DRIVERS_ATLAS_LAMBDA_PASSWORD}" \
LAMBDA_STACK_NAME="dbx-ruby-lambda" \
MONGODB_VERSION="7.0" \
task_id="${task_id}" \
execution="${execution}" \
$DRIVERS_TOOLS/.evergreen/atlas/setup-atlas-cluster.sh
$DRIVERS_TOOLS/.evergreen/atlas/setup-atlas-cluster.sh
- command: expansions.update
params:
file: src/atlas-expansion.yml
Expand All @@ -502,16 +504,10 @@ task_groups:
working_dir: "src"
script: |
${PREPARE_SHELL}

DRIVERS_ATLAS_PUBLIC_API_KEY="${DRIVERS_ATLAS_PUBLIC_API_KEY}" \
DRIVERS_ATLAS_PRIVATE_API_KEY="${DRIVERS_ATLAS_PRIVATE_API_KEY}" \
DRIVERS_ATLAS_GROUP_ID="${DRIVERS_ATLAS_GROUP_ID}" \
LAMBDA_STACK_NAME="dbx-ruby-lambda" \
task_id="${task_id}" \
execution="${execution}" \
$DRIVERS_TOOLS/.evergreen/atlas/teardown-atlas-cluster.sh
$DRIVERS_TOOLS/.evergreen/atlas/teardown-atlas-cluster.sh
tasks:
- test-full-atlas-task
- test-faas-aws-lambda-task

- name: testgcpkms_task_group
setup_group_can_fail_task: true
Expand Down Expand Up @@ -640,6 +636,24 @@ tasks:
script: |
${PREPARE_SHELL}
MONGODB_URI="${MONGODB_URI}" .evergreen/run-tests-atlas-full.sh
- name: "test-faas-aws-lambda-task"
commands:
- command: ec2.assume_role
params:
role_arn: ${LAMBDA_AWS_ROLE_ARN}
duration_seconds: 3600
- command: shell.exec
type: test
params:
working_dir: src
shell: bash
script: |
${PREPARE_SHELL}

TEST_LAMBDA_DIRECTORY="${PROJECT_DIRECTORY}/spec/support/faas/app/aws_lambda" \
AWS_REGION="us-east-1" \
MONGODB_URI="${MONGODB_URI}" \
.evergreen/aws_lambda/run-deployed-lambda-aws-tests.sh
- name: "testgcpkms-task"
commands:
- command: shell.exec
Expand Down
52 changes: 33 additions & 19 deletions .evergreen/config/common.yml.erb
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,18 @@ functions:
export SERVERLESS_API_PRIVATE_KEY="${SERVERLESS_API_PRIVATE_KEY}"
export SERVERLESS_ATLAS_USER="${SERVERLESS_ATLAS_USER}"
export SERVERLESS_ATLAS_PASSWORD="${SERVERLESS_ATLAS_PASSWORD}"
export LAMBDA_AWS_ROLE_ARN="${LAMBDA_AWS_ROLE_ARN}"

# For starting/stopping/managing an atlas cluster
export DRIVERS_ATLAS_PUBLIC_API_KEY="${DRIVERS_ATLAS_PUBLIC_API_KEY}"
export DRIVERS_ATLAS_PRIVATE_API_KEY="${DRIVERS_ATLAS_PRIVATE_API_KEY}"
export DRIVERS_ATLAS_GROUP_ID="${DRIVERS_ATLAS_GROUP_ID}"
export DRIVERS_ATLAS_LAMBDA_USER="${DRIVERS_ATLAS_LAMBDA_USER}"
export DRIVERS_ATLAS_LAMBDA_PASSWORD="${DRIVERS_ATLAS_LAMBDA_PASSWORD}"
export LAMBDA_STACK_NAME="dbx-ruby-lambda"
export MONGODB_VERSION="7.0"
export task_id="${task_id}"
export execution="${execution}"

# Needed for generating temporary aws credentials.
if [ -n "${FLE}" ];
Expand Down Expand Up @@ -478,17 +490,7 @@ task_groups:
working_dir: "src"
script: |
${PREPARE_SHELL}

DRIVERS_ATLAS_PUBLIC_API_KEY="${DRIVERS_ATLAS_PUBLIC_API_KEY}" \
DRIVERS_ATLAS_PRIVATE_API_KEY="${DRIVERS_ATLAS_PRIVATE_API_KEY}" \
DRIVERS_ATLAS_GROUP_ID="${DRIVERS_ATLAS_GROUP_ID}" \
DRIVERS_ATLAS_LAMBDA_USER="${DRIVERS_ATLAS_LAMBDA_USER}" \
DRIVERS_ATLAS_LAMBDA_PASSWORD="${DRIVERS_ATLAS_LAMBDA_PASSWORD}" \
LAMBDA_STACK_NAME="dbx-ruby-lambda" \
MONGODB_VERSION="7.0" \
task_id="${task_id}" \
execution="${execution}" \
$DRIVERS_TOOLS/.evergreen/atlas/setup-atlas-cluster.sh
$DRIVERS_TOOLS/.evergreen/atlas/setup-atlas-cluster.sh
- command: expansions.update
params:
file: src/atlas-expansion.yml
Expand All @@ -499,16 +501,10 @@ task_groups:
working_dir: "src"
script: |
${PREPARE_SHELL}

DRIVERS_ATLAS_PUBLIC_API_KEY="${DRIVERS_ATLAS_PUBLIC_API_KEY}" \
DRIVERS_ATLAS_PRIVATE_API_KEY="${DRIVERS_ATLAS_PRIVATE_API_KEY}" \
DRIVERS_ATLAS_GROUP_ID="${DRIVERS_ATLAS_GROUP_ID}" \
LAMBDA_STACK_NAME="dbx-ruby-lambda" \
task_id="${task_id}" \
execution="${execution}" \
$DRIVERS_TOOLS/.evergreen/atlas/teardown-atlas-cluster.sh
$DRIVERS_TOOLS/.evergreen/atlas/teardown-atlas-cluster.sh
tasks:
- test-full-atlas-task
- test-faas-aws-lambda-task

- name: testgcpkms_task_group
setup_group_can_fail_task: true
Expand Down Expand Up @@ -637,6 +633,24 @@ tasks:
script: |
${PREPARE_SHELL}
MONGODB_URI="${MONGODB_URI}" .evergreen/run-tests-atlas-full.sh
- name: "test-faas-aws-lambda-task"
commands:
- command: ec2.assume_role
params:
role_arn: ${LAMBDA_AWS_ROLE_ARN}
duration_seconds: 3600
- command: shell.exec
type: test
params:
working_dir: src
shell: bash
script: |
${PREPARE_SHELL}

TEST_LAMBDA_DIRECTORY="${PROJECT_DIRECTORY}/spec/support/faas/app/aws_lambda" \
AWS_REGION="us-east-1" \
MONGODB_URI="${MONGODB_URI}" \
.evergreen/aws_lambda/run-deployed-lambda-aws-tests.sh
- name: "testgcpkms-task"
commands:
- command: shell.exec
Expand Down
26 changes: 26 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,29 @@ namespace :docs do
end

load 'profile/benchmarking/rake/tasks.rake'

desc 'Build and validate the evergreen config'
task eg: %w[ eg:build eg:validate ]

# 'eg' == 'evergreen', but evergreen is too many letters for convenience
namespace :eg do
desc 'Builds the .evergreen/config.yml file from the templates'
task :build do
ruby '.evergreen/update-evergreen-configs'
end

desc 'Validates the .evergreen/config.yml file'
task :validate do
system 'evergreen validate --project mongo-ruby-driver .evergreen/config.yml'
end

desc 'Updates the evergreen executable to the latest available version'
task :update do
system 'evergreen get-update --install'
end

desc 'Runs the current branch as an evergreen patch'
task :patch do
system 'evergreen patch --uncommitted --project mongo-ruby-driver --browse --auto-description --yes'
end
end
8 changes: 8 additions & 0 deletions spec/support/faas/app/aws_lambda/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
source "https://rubygems.org"

gem "httparty"

group :test do
gem "test-unit"
gem "mocha"
end
18 changes: 18 additions & 0 deletions spec/support/faas/app/aws_lambda/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# MongoDB FaaS Test Application for AWS Lambda

This folder contains source code and supporting files for a serverless test application to be run via AWS Lambda.

For information about how this test application is intended to be used, please see: https://github.com/mongodb/specifications/blob/master/source/faas-automated-testing/faas-automated-testing.rst#implementing-automated-faas-tests


## Running Locally

To run this locally, follow the instructions in the link above. If you aren't running an x86-64 architecture locally (e.g. Apple M1, etc.) you will need to bundle the gems via Docker so that gems with native components (e.g. BSON-Ruby) are built for the appropriate architecture.

The included `bundle-gems.sh` script is intended to help with this. To use it, change to the `mongodb` subdirectory, and then invoke the helper script:

~~~
faas/app/aws_lambda/mongodb $ ../bundle-gems.sh
~~~

This will invoke `bundle install` via a Docker container and create a `vendor` subdirectory. Once that is done, return to the `faas/app/aws_lambda` folder and run `sam build` and `sam invoke` (as described in the `faas-automated-testing` specification).
16 changes: 16 additions & 0 deletions spec/support/faas/app/aws_lambda/bundle-gems.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/bin/sh

# source:
# https://dev.to/aws-builders/building-aws-ruby-lambdas-that-require-gems-with-native-extension-17h

dir=`pwd`

bundle config set --local path 'vendor/bundle'
bundle config set --local deployment 'true'

docker run --platform=linux/amd64 \
-e BUNDLE_SILENCE_ROOT_WARNING=1 \
-v $dir:$dir \
-w $dir \
public.ecr.aws/sam/build-ruby3.2 \
bundle install
7 changes: 7 additions & 0 deletions spec/support/faas/app/aws_lambda/mongodb/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

source "https://rubygems.org"

gem "mongo"

ruby '~> 3.2.0'
28 changes: 28 additions & 0 deletions spec/support/faas/app/aws_lambda/mongodb/app.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# frozen_string_literal: true

require 'mongo'
require 'faas_test/runner'

# Helpful resources:
# https://dev.to/aws-builders/building-aws-ruby-lambdas-that-require-gems-with-native-extension-17h

# Parameters
# ----------
# event: Hash, required
# API Gateway Lambda Proxy Input Format
# Event doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format
#
# context: object, required
# Lambda Context runtime methods and attributes
# Context doc: https://docs.aws.amazon.com/lambda/latest/dg/ruby-context.html
def lambda_handler(event:, context:)
client = Mongo::Client.new(ENV['MONGODB_URI'])
runner = FaaSTest::Runner.new(client)

results = runner.run

{
statusCode: 200,
body: results.to_json
}
end
68 changes: 68 additions & 0 deletions spec/support/faas/app/aws_lambda/mongodb/faas_test/runner.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# frozen_string_literal: true

require 'faas_test/subscribers/heartbeat'
require 'faas_test/subscribers/command'
require 'faas_test/subscribers/connection_pool'

module FaaSTest
class Runner
extend Forwardable

attr_reader :client
attr_reader :collection_name

def_delegators :client, :database

def initialize(client)
@client = client
@collection_name = BSON::ObjectId.new.to_s

prepare_subscriptions!
end

def run
perform_test
compile_results
end

private

attr_reader :heartbeat_subscriber
attr_reader :command_subscriber
attr_reader :connection_pool_subscriber

def compile_results
{
heartbeat: {
started: heartbeat_subscriber.started_count,
succeeded: heartbeat_subscriber.succeeded_count,
failed: heartbeat_subscriber.failed_count,
durations: heartbeat_subscriber.durations,
},
command: {
durations: command_subscriber.durations,
},
connections: {
open: connection_pool_subscriber.open_connections,
}
}
end

def perform_test
result = database[collection_name].insert_one({ a: 1, b: '2' })
id = result.inserted_id

database[collection_name].delete_one(_id: id)
end

def prepare_subscriptions!
@heartbeat_subscriber = FaaSTest::Subscribers::Heartbeat.new
@command_subscriber = FaaSTest::Subscribers::Command.new
@connection_pool_subscriber = FaaSTest::Subscribers::ConnectionPool.new

client.subscribe(Mongo::Monitoring::SERVER_HEARTBEAT, heartbeat_subscriber)
client.subscribe(Mongo::Monitoring::COMMAND, command_subscriber)
client.subscribe(Mongo::Monitoring::CONNECTION_POOL, connection_pool_subscriber)
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# frozen_string_literal: true

module FaaSTest
module Subscribers
class Command
attr_reader :durations

def initialize
@durations = []
end

def started(_event)
end

def succeeded(event)
@durations.push event.duration
end

def failed(_event)
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# frozen_string_literal: true

module FaaSTest
module Subscribers
class ConnectionPool
attr_reader :open_connections

def initialize
@open_connections = 0
end

def published(event)
case event
when Mongo::Monitoring::Event::Cmap::ConnectionCreated
@open_connections += 1
when Mongo::Monitoring::Event::Cmap::ConnectionClosed
@open_connections -= 1
end
end
end
end
end
Loading