architect/functions

sandbox in unit-tests, issue with requiring @architect/functions in jest

konsumer opened this issue · 5 comments

Describe the issue
If I put this in my unit-test:

const arc = require('@architect/functions')

I get this error:

Timeout - Async callback was not invoked within the 5000ms timeout specified by jest.setTimeout.Error: Timeout - Async callback was not invoked within the 5000ms timeout specified by jest.setTimeout.

Steps to reproduce

Make a test like this:

/* global describe, it, expect, beforeAll, afterAll */

// this causes async-hang
const arc = require('@architect/functions')

const sandbox = require('@architect/sandbox')

beforeAll(async () => {
  console.log('Sandbox: start')
  await sandbox.start({ quiet: true })
})
afterAll(async () => {
  console.log('Sandbox: end')
  await sandbox.end()
})

describe('jest', () => {
  it('should have unit-tests', async () => {
    expect(1 + 1).toEqual(2)
  })
})

run jest.

If you comment out the require of @architect/functions, it runs fine and start/stops the sandbox (on 1.5.9-RC.2.)

Expected behavior
I expect no breaking async side-effects on import, so there is no error.

Solutions

I narrowed the problem down to 3 lines in 2 files, in @architect/functions/src/tables/, db.js & doc.js:

both have code like this:

if (!testing) {
  const agent = new https.Agent({
    keepAlive: true,
    maxSockets: 50,
    rejectUnauthorized: true
  })
  aws.config.update({
     httpOptions: { agent }
  })
}

The offending bit is this:

  aws.config.update({
     httpOptions: { agent }
  })

If I remove the whole testing logic-branch (no custom agent) in both files, the issue goes away, but I haven't tested if the client still functions.

{
"devDependencies": {
    "@architect/sandbox": "1.5.9-RC.2",
    "jest": "^25.1.0"
  },
  "dependencies": {
    "@architect/functions": "^3.5.0"
  }
}
node 13.7.0

I dunno if it's related, but if I do console.log(await arc.tables()) in the same unit-test, I get this:

{ reflect: [AsyncFunction: reflect] }

with this .arc:

@app
jest-example

@tables
jesttest
  PK *String        # Primary Identifier
  SK **String       # ParamIndex1

I gave up, and just switched to mocha. It works fine, including arc.tables().

const arc = require('@architect/functions')
const sandbox = require('@architect/sandbox')

before(async () => {
  await sandbox.start({ quiet: true })
})
after(async () => {
  await sandbox.end()
})

I think this will still be an issue for other tools, but for my particular use-case, I can live with mocha.

ok cool, this is super helpful! thank you for the detail and investigation. we will crack this!

we do the keepalive stuff in dynamo because it results in drastically better performance in lambda land but it appears there is a magic env var AWS_NODEJS_CONNECTION_REUSE_ENABLED that can do the same thing

https://theburningmonk.com/2019/02/lambda-optimization-tip-enable-http-keep-alive/

will play around w this and report back

Should be fixed in #248 – please check it out in the latest RC! npm i @architect/functions@RC

Released in 3.7.2!