-
-
Notifications
You must be signed in to change notification settings - Fork 795
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
go-runner implementation #1320
go-runner implementation #1320
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
import { EOL } from 'os' | ||
import { promises as fsPromises } from 'fs' | ||
import { sep, resolve, parse as pathParse } from 'path' | ||
import execa, { sync } from 'execa' | ||
|
||
const { writeFile, readFile, mkdir, rmdir } = fsPromises | ||
const { parse, stringify } = JSON | ||
const { cwd } = process | ||
|
||
const PAYLOAD_IDENTIFIER = 'offline_payload' | ||
|
||
export default class GoRunner { | ||
#env = null | ||
#handlerPath = null | ||
#tmpPath = null | ||
#tmpFile = null | ||
#goEnv = null | ||
|
||
constructor(funOptions, env, v3Utils) { | ||
const { handlerPath } = funOptions | ||
|
||
this.#env = env | ||
this.#handlerPath = handlerPath | ||
|
||
if (v3Utils) { | ||
this.log = v3Utils.log | ||
this.progress = v3Utils.progress | ||
this.writeText = v3Utils.writeText | ||
this.v3Utils = v3Utils | ||
} | ||
|
||
// Make sure we have the mock-lambda runner | ||
sync('go', ['get', 'github.com/icarus-sullivan/mock-lambda@e065469']) | ||
} | ||
|
||
async cleanup() { | ||
try { | ||
await rmdir(this.#tmpPath, { recursive: true }) | ||
} catch (e) { | ||
// @ignore | ||
} | ||
|
||
this.#tmpFile = null | ||
this.#tmpPath = null | ||
} | ||
|
||
_parsePayload(value) { | ||
const log = [] | ||
let payload | ||
|
||
for (const item of value.split(EOL)) { | ||
if (item.indexOf(PAYLOAD_IDENTIFIER) === -1) { | ||
log.push(item) | ||
} else if (item.indexOf(PAYLOAD_IDENTIFIER) !== -1) { | ||
try { | ||
const { | ||
offline_payload: { success, error }, | ||
} = parse(item) | ||
if (success) { | ||
payload = success | ||
} else if (error) { | ||
payload = error | ||
} | ||
} catch (err) { | ||
// @ignore | ||
} | ||
} | ||
} | ||
|
||
// Log to console in case engineers want to see the rest of the info | ||
if (this.log) { | ||
this.log(log.join(EOL)) | ||
} else { | ||
console.log(log.join(EOL)) | ||
} | ||
|
||
return payload | ||
} | ||
|
||
async run(event, context) { | ||
const { dir } = pathParse(this.#handlerPath) | ||
const handlerCodeRoot = dir.split(sep).slice(0, -1).join(sep) | ||
const handlerCode = await readFile(`${this.#handlerPath}.go`, 'utf8') | ||
this.#tmpPath = resolve(handlerCodeRoot, 'tmp') | ||
this.#tmpFile = resolve(this.#tmpPath, 'main.go') | ||
|
||
const out = handlerCode.replace( | ||
'"github.com/aws/aws-lambda-go/lambda"', | ||
'lambda "github.com/icarus-sullivan/mock-lambda"', | ||
) | ||
Comment on lines
+87
to
+90
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Clone code and swap out lambda import, mock-lambda looks for the |
||
|
||
try { | ||
await mkdir(this.#tmpPath, { recursive: true }) | ||
} catch (e) { | ||
// @ignore | ||
} | ||
|
||
try { | ||
await writeFile(this.#tmpFile, out, 'utf8') | ||
} catch (e) { | ||
// @ignore | ||
} | ||
|
||
// Get go env to run this locally | ||
if (!this.#goEnv) { | ||
const goEnvResponse = await execa('go', ['env'], { | ||
stdio: 'pipe', | ||
encoding: 'utf-8', | ||
}) | ||
|
||
const goEnvString = goEnvResponse.stdout || goEnvResponse.stderr | ||
this.#goEnv = goEnvString.split(EOL).reduce((a, b) => { | ||
const [k, v] = b.split('="') | ||
// eslint-disable-next-line no-param-reassign | ||
a[k] = v ? v.slice(0, -1) : '' | ||
return a | ||
}, {}) | ||
} | ||
|
||
// Remove our root, since we want to invoke go relatively | ||
const cwdPath = `${this.#tmpFile}`.replace(`${cwd()}${sep}`, '') | ||
const { stdout, stderr } = await execa(`go`, ['run', cwdPath], { | ||
stdio: 'pipe', | ||
env: { | ||
...this.#env, | ||
...this.#goEnv, | ||
AWS_LAMBDA_LOG_GROUP_NAME: context.logGroupName, | ||
AWS_LAMBDA_LOG_STREAM_NAME: context.logStreamName, | ||
AWS_LAMBDA_FUNCTION_NAME: context.functionName, | ||
AWS_LAMBDA_FUNCTION_MEMORY_SIZE: context.memoryLimitInMB, | ||
AWS_LAMBDA_FUNCTION_VERSION: context.functionVersion, | ||
LAMBDA_EVENT: stringify(event), | ||
LAMBDA_TEST_EVENT: `${event}`, | ||
LAMBDA_CONTEXT: stringify(context), | ||
IS_LAMBDA_AUTHORIZER: | ||
event.type === 'REQUEST' || event.type === 'TOKEN', | ||
IS_LAMBDA_REQUEST_AUTHORIZER: event.type === 'REQUEST', | ||
IS_LAMBDA_TOKEN_AUTHORIZER: event.type === 'TOKEN', | ||
Comment on lines
+135
to
+138
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added initial support for custom authorizers |
||
PATH: process.env.PATH, | ||
}, | ||
encoding: 'utf-8', | ||
}) | ||
|
||
// Clean up after we created the temporary file | ||
await this.cleanup() | ||
|
||
if (stderr) { | ||
return stderr | ||
} | ||
|
||
return this._parsePayload(stdout) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { default } from './GoRunner.js' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import execa from 'execa' | ||
|
||
export default async function checkGoVersion() { | ||
let goVersion | ||
try { | ||
const { stdout } = await execa('go', ['version']) | ||
if (stdout.match(/go1.\d+/g)) { | ||
goVersion = '1.x' | ||
} | ||
} catch (err) { | ||
// @ignore | ||
} | ||
|
||
return goVersion | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
bin |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
module serverless-offline-go1.x-test | ||
|
||
go 1.13 | ||
|
||
require ( | ||
github.com/aws/aws-lambda-go v1.28.0 | ||
github.com/icarus-sullivan/mock-lambda v0.0.0-20220115083805-e065469e964a // indirect | ||
github.com/urfave/cli v1.22.1 // indirect | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= | ||
github.com/aws/aws-lambda-go v1.13.2 h1:8lYuRVn6rESoUNZXdbCmtGB4bBk4vcVYojiHjE4mMrM= | ||
github.com/aws/aws-lambda-go v1.13.2/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= | ||
github.com/aws/aws-lambda-go v1.28.0 h1:fZiik1PZqW2IyAN4rj+Y0UBaO1IDFlsNo9Zz/XnArK4= | ||
github.com/aws/aws-lambda-go v1.28.0/go.mod h1:jJmlefzPfGnckuHdXX7/80O3BvUUi12XOkbv4w9SGLU= | ||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= | ||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= | ||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= | ||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/icarus-sullivan/mock-lambda v0.0.0-20220114085425-44091545252e h1:cPv6jHZPqHlu73UmtFEVPRNHGnSrd43OKwpQKVktLcs= | ||
github.com/icarus-sullivan/mock-lambda v0.0.0-20220114085425-44091545252e/go.mod h1:2iuLAENWZqxe/B6XUDWw/3ioQ9d1fwhgFTlwVeIBpzY= | ||
github.com/icarus-sullivan/mock-lambda v0.0.0-20220115083805-e065469e964a h1:gmFO6gLHZkdJlkZ41QiQ5tzH8LORPVJCuKk6YKyquU0= | ||
github.com/icarus-sullivan/mock-lambda v0.0.0-20220115083805-e065469e964a/go.mod h1:2iuLAENWZqxe/B6XUDWw/3ioQ9d1fwhgFTlwVeIBpzY= | ||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= | ||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= | ||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= | ||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= | ||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= | ||
github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= | ||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | ||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { platform } from 'os' | ||
import { resolve } from 'path' | ||
import fetch from 'node-fetch' | ||
import { joinUrl, setup, teardown } from '../../_testHelpers/index.js' | ||
|
||
jest.setTimeout(180000) | ||
|
||
const _describe = | ||
process.env.GO1X_DETECTED && platform() !== 'win32' ? describe : describe.skip | ||
|
||
_describe('Go 1.x with GoRunner', () => { | ||
// init | ||
beforeAll(() => | ||
setup({ | ||
servicePath: resolve(__dirname), | ||
}), | ||
) | ||
|
||
// cleanup | ||
afterAll(() => teardown()) | ||
|
||
// | ||
;[ | ||
{ | ||
description: 'should work with go1.x', | ||
expected: { | ||
message: 'Hello Go 1.x!', | ||
}, | ||
path: '/dev/hello', | ||
}, | ||
].forEach(({ description, expected, path }) => { | ||
test(description, async () => { | ||
const url = joinUrl(TEST_BASE_URL, path) | ||
const response = await fetch(url) | ||
const json = await response.json() | ||
|
||
expect(json).toEqual(expected) | ||
}) | ||
}) | ||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/aws/aws-lambda-go/events" | ||
"github.com/aws/aws-lambda-go/lambda" | ||
) | ||
|
||
func Handler(ctx context.Context, req events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) { | ||
return events.APIGatewayProxyResponse{ | ||
Body: "{\"message\": \"Hello Go 1.x!\"}", | ||
StatusCode: 200, | ||
}, nil | ||
} | ||
|
||
func main() { | ||
lambda.Start(Handler) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
service: docker-go-1.x-tests | ||
|
||
plugins: | ||
- ../../../../ | ||
|
||
provider: | ||
memorySize: 128 | ||
name: aws | ||
region: us-east-1 # default | ||
runtime: go1.x | ||
stage: dev | ||
versionFunctions: false | ||
|
||
functions: | ||
hello: | ||
events: | ||
- http: | ||
method: get | ||
path: hello | ||
handler: hello/main.go |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Constructors aren't created in an async manner, so using sync here only.