Skip to content
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

make ruby tests pass #53

Open
wants to merge 4 commits into
base: PRODUCT-959/fun-add-ruby
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ implemented are:
* `python3.6` for Python Lambda functions using a downloaded Python v3.6.8 binary
* `python3.7` for Python Lambda functions using a downloaded Python v3.7.2 binary
* `ruby` for Ruby Lambda functions using the system `ruby` binary
* `ruby2.5` for Ruby Lambda functions using a downloaded Ruby v2.5.5 binary
* `ruby2.7` for Ruby Lambda functions using a downloaded Ruby v2.7.0 binary
* `go1.x` for Lambda functions written in Go - binary must be compiled for your platform
* `provided` for [custom runtimes][]

Expand Down
57 changes: 57 additions & 0 deletions src/install-ruby.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import createDebug from 'debug';
import execa from 'execa';
const debug = createDebug('@zeit/fun:install-ruby');

export async function installRVM(version: string, dest: string): Promise<void> {
try {
debug('Checking for RVM');
await execa(`${dest}/bin/rvm`);
debug('RVM present');

const versionsString = (await execa.command(
`${dest}/bin/rvm list strings`
)).stdout;

if (!versionsString.includes(version)) {
debug(`Installing ruby version ${version}`);
await execa.command(`${dest}/bin/rvm install ${version}`);
}
} catch (error) {
debug(error);

debug(`Installing RVM with ruby version ${version}`);
await execa.command(
`curl -sSL https://get.rvm.io | bash -s -- --path ${dest}/rvm_cache --ruby=${version}`,
{ shell: true, stdio: 'inherit' }
);
}

return;
}

export async function copyInstalledRuby(
version: string,
dest: string
): Promise<void> {
debug('Copying ruby version to cachedir/ruby_bin');
await execa.command(
`cp -r ${dest}/rvm_cache/rubies/ruby-${version} ${dest}/ruby-${version}`
);
return;
}

export async function installRuby(
dest: string,
version: string
): Promise<void> {
return new Promise(async (resolve, reject) => {
try {
await installRVM(version, dest);
await copyInstalledRuby(version, dest);
resolve();
} catch (error) {
debug(error);
reject();
}
});
}
4 changes: 4 additions & 0 deletions src/runtimes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import * as python27 from './runtimes/python2.7';
import * as python3 from './runtimes/python3';
import * as python36 from './runtimes/python3.6';
import * as python37 from './runtimes/python3.7';
import * as ruby25 from './runtimes/ruby2.5';
import * as ruby27 from './runtimes/ruby2.7';

const debug = createDebug('@zeit/fun:runtimes');
const runtimesDir = join(__dirname, 'runtimes');
Expand Down Expand Up @@ -56,6 +58,8 @@ createRuntime(runtimes, 'python3', python3);
createRuntime(runtimes, 'python3.6', python36);
createRuntime(runtimes, 'python3.7', python37);
createRuntime(runtimes, 'ruby');
createRuntime(runtimes, 'ruby2.5', ruby25);
createRuntime(runtimes, 'ruby2.7', ruby27);

/**
* Reads the file path `f` as an ascii string.
Expand Down
14 changes: 5 additions & 9 deletions src/runtimes/ruby/bootstrap.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,14 @@ def call_handler(request:, context:)
end

class LambdaServer
LAMBDA_SERVER_ADDRESS = "http://127.0.0.1:9001/2018-06-01"

LONG_TIMEOUT = 1_000_000

def initialize(server_address: LAMBDA_SERVER_ADDRESS)
@server_address = server_address
def initialize
@server_address = ENV['AWS_LAMBDA_RUNTIME_API']
end

def next_invocation
next_invocation_uri = URI(@server_address + "/runtime/invocation/next")
next_invocation_uri = URI("http://#{@server_address}/2018-06-01/runtime/invocation/next")
begin
http = Net::HTTP.new(next_invocation_uri.host, next_invocation_uri.port)
http.read_timeout = LONG_TIMEOUT
Expand All @@ -86,9 +84,7 @@ def next_invocation
end

def send_response(request_id:, response_object:, content_type: 'application/json')
response_uri = URI(
@server_address + "/runtime/invocation/#{request_id}/response"
)
response_uri = URI("http://#{@server_address}/2018-06-01/runtime/invocation/#{request_id}/response")
begin
# unpack IO at this point
if content_type == 'application/unknown'
Expand Down Expand Up @@ -288,7 +284,7 @@ def marshall_response(method_response)

begin
@lambda_handler = LambdaHandler.new(env_handler: @env_handler)
require @lambda_handler.handler_file_name
require "#{ENV["LAMBDA_TASK_ROOT"]}/#{@lambda_handler.handler_file_name}"
rescue Exception => e # which includes LoadError or any exception within static user code
runtime_loop_active = false
exit_code = -4
Expand Down
13 changes: 13 additions & 0 deletions src/runtimes/ruby2.5/bootstrap
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/sh
set -eu

# Ensure the downloaded Ruby version is used
export PATH="$LAMBDA_RUNTIME_DIR/ruby-2.5.5/bin:$PATH"

# Ensure libraries can be found on linux
export LD_LIBRARY_PATH="$LAMBDA_RUNTIME_DIR/ruby-2.5.5/lib"

# Execute the "ruby" runtime bootstrap
export LAMBDA_RUNTIME_DIR="$(dirname "$0")/../ruby"

exec "$LAMBDA_RUNTIME_DIR/bootstrap" "$@"
7 changes: 7 additions & 0 deletions src/runtimes/ruby2.5/bootstrap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { join } from 'path';
import { spawn } from 'child_process';

const rubyBin = join(__dirname, 'bin', 'ruby');

const bootstrap = join(__dirname, '..', 'ruby', 'bootstrap.rb');
spawn(rubyBin, [bootstrap], { stdio: 'inherit' });
10 changes: 10 additions & 0 deletions src/runtimes/ruby2.5/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Runtime } from '../../types';
import { installRuby } from '../../install-ruby';
import { runtimes, initializeRuntime } from '../../runtimes';

export async function init({ cacheDir }: Runtime): Promise<void> {
await Promise.all([
initializeRuntime(runtimes.ruby),
installRuby(cacheDir, '2.5.5')
]);
}
13 changes: 13 additions & 0 deletions src/runtimes/ruby2.7/bootstrap
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/sh
set -eu

# Ensure the downloaded Ruby version is used
export PATH="$LAMBDA_RUNTIME_DIR/ruby-2.7.0/bin:$PATH"

# Ensure libraries can be found on linux
export LD_LIBRARY_PATH="$LAMBDA_RUNTIME_DIR/ruby-2.7.0/lib"

# Execute the "ruby" runtime bootstrap
export LAMBDA_RUNTIME_DIR="$(dirname "$0")/../ruby"

exec "$LAMBDA_RUNTIME_DIR/bootstrap" "$@"
7 changes: 7 additions & 0 deletions src/runtimes/ruby2.7/bootstrap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { join } from 'path';
import { spawn } from 'child_process';

const rubyBin = join(__dirname, 'bin', 'ruby');

const bootstrap = join(__dirname, '..', 'ruby', 'bootstrap.rb');
spawn(rubyBin, [bootstrap], { stdio: 'inherit' });
10 changes: 10 additions & 0 deletions src/runtimes/ruby2.7/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Runtime } from '../../types';
import { installRuby } from '../../install-ruby';
import { runtimes, initializeRuntime } from '../../runtimes';

export async function init({ cacheDir }: Runtime): Promise<void> {
await Promise.all([
initializeRuntime(runtimes.ruby),
installRuby(cacheDir, '2.7.0')
]);
}
24 changes: 1 addition & 23 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,8 @@
export type RuntimeLiteral =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we want to remove this though 🤔

| 'nodejs'
| 'nodejs4.3'
| 'nodejs6.10'
| 'nodejs8.10'
| 'nodejs10.x'
| 'nodejs12.x'
| 'java8'
| 'python2.7'
| 'python'
| 'python3'
| 'python3.6'
| 'python3.7'
| 'dotnetcore1.0'
| 'dotnetcore2.0'
| 'dotnetcore2.1'
| 'nodejs4.3-edge'
| 'go1.x'
| 'ruby'
| 'ruby2.5'
| 'provided';

export interface LambdaParams {
FunctionName?: string;
Code: { ZipFile?: Buffer | string; Directory?: string };
Handler: string;
Runtime: RuntimeLiteral;
Runtime: string; // nodejs | nodejs4.3 | nodejs6.10 | nodejs8.10 | nodejs10.x | nodejs12.x | java8 | python2.7 | python3.6 | python3.7 | dotnetcore1.0 | dotnetcore2.0 | dotnetcore2.1 | nodejs4.3-edge | go1.x | ruby2.5 | ruby2.7 | provided;
Provider?: string; // native | docker
Environment?: { Variables: object };
MemorySize?: number; // The amount of memory that your function has access to. Increasing the function's memory also increases it's CPU allocation. The default value is 128 MB. The value must be a multiple of 64 MB.
Expand Down
11 changes: 6 additions & 5 deletions test/functions/ruby-hello/handler.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
require 'json'

def handler(event:, context:):
return {
statusCode: 200,
body: JSON.generate('Hello from ruby')
}
def handler(event:, context:)
return {
statusCode: 200,
body: JSON.generate({hello_text: "Hello from ruby"})
}
end
jameselkins marked this conversation as resolved.
Show resolved Hide resolved
6 changes: 6 additions & 0 deletions test/functions/ruby-version/handler.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
def handler(event:, context:)
return {
statusCode: 200,
body: RUBY_VERSION
}
end
37 changes: 36 additions & 1 deletion test/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,42 @@ export const test_ruby_hello = testInvoke(
}),
async fn => {
const payload = await fn();
assert.equal(payload['body'], 'Hello from ruby');
assert.equal(
JSON.parse(payload['body'])['hello_text'],
'Hello from ruby'
);
}
);

// `ruby2.5` runtime
export const test_ruby25_version = testInvoke(
() =>
createFunction({
Code: {
Directory: __dirname + '/functions/ruby-version'
},
Handler: 'handler.handler',
Runtime: 'ruby2.5'
}),
async fn => {
const payload = await fn();
assert.equal(payload['body'], '2.5.5');
}
);

// `ruby2.7` runtime
export const test_ruby27_version = testInvoke(
() =>
createFunction({
Code: {
Directory: __dirname + '/functions/ruby-version'
},
Handler: 'handler.handler',
Runtime: 'ruby2.7'
}),
async fn => {
const payload = await fn();
assert.equal(payload['body'], '2.7.0');
}
);

Expand Down