Aws-xray-sdk-node: Failed to get the current sub/segment when writing unit tests

Created on 4 Apr 2019  路  12Comments  路  Source: aws/aws-xray-sdk-node

I'm trying to write a unit tests for a function which is traced. I've been stuck trying to bootstrap the test.

src/mysql.js:

module.exports.executeMysqlQuery = async (pool, sql, params = []) => {
    return new Promise(async (resolve, reject) => {
        xray.captureAsyncFunc('mysql-query', async (subsegment) => {
            subsegment.addAnnotation('query', sql);
            try {
                const results = await pool.execute(sql, params);
                subsegment.close();
                resolve(results);
            } catch (error) {
                reject(error);
                subsegment.close(error);
            }
        });
    });
};

tests/mysqlTest.js

const {expect} = require('chai');
const mysql = require('mysql2');
const {executeMysqlQuery} = require('../src/mysql');
const xray = require('aws-xray-sdk');


describe('mysql', () => {
    const sandbox = require('sinon').createSandbox();
    const namespace = xray.getNamespace();
    const segment = new xray.Segment('root');

    beforeEach(async () => {
        return await namespace.run(() => {
            xray.setSegment(segment);
        });
    });

    afterEach(() => {
        sandbox.verify();
        sandbox.restore();
        segment.close();
    });

    context('executeMysqlQuery', () => {
        it('Should Execute Query', async () => {
            const name = 'manchuck';
            const fields = ['id', 'name'];
            const expected = [{id: 0, name: name}];
            const results = [expected, fields];
            const pool = mysql.createPool({host: 'localhost'});

            const poolMock = sandbox.mock(pool);
            poolMock.
                expects('execute').
                once().
                withArgs('select * from users where name = ?', [name]).
                resolves(results);

            const actualResults = await executeMysqlQuery(
                pool,
                'select * from users where name = ?',
                [name],
            );

            expect(actualResults).deep.eq(expected);
        });
    });
});

When executing the test, I'm getting Error: Failed to get the current sub/segment from the context..

question

Most helpful comment

Hi @manchuck,
Sorry for the delayed response, and I apologize for the frustration you're experiencing. While it does not strictly disable X-Ray, you may prevent the errors you are receiving from failing your unit tests using the ContextMissingStrategy. This can be done by setting the AWS_XRAY_CONTEXT_MISSING environment variable to LOG_ERROR. This emits a warning to the logs when the SDK encounters the error you're receiving rather than causing a runtime error. Read more about our environment variables here (but please note the log level setting feature has not been released to NPM yet).

Additionally, you can set a custom context missing strategy with a function of your own (e.g. a no-op) using this API. Sorry for the lack of formal documentation, please reach out again if you need further clarifications. It should be noted that setting the context missing environment variable will override any custom function provided programmatically.

All 12 comments

I'm running into this as well when running jest in an automated unit test run with codebuild.

@manchuck
Are you using the experimental version of the SDK? That version supports async/await.

You can install it using: npm install --save aws-xray-sdk@experimental

@chrisradek Yes I am using 2.1.0-experimental.1

I had the same issue, but I'm testing with jest.
For the workaround I just mocked the captureAsyncFunc.

xray.captureAsyncFunc = jest.fn((name, fn) => {
    fn({
        addAnnotation: () => {},
        close: () => {},
        // ... add whatever you use on the subsegment
    });
});

Maybe with chai-spies you could do something similar.

Same problem here, I'm also using a jest mockup like that:

import xray from "aws-xray-sdk-core";

jest.spyOn(xray, "captureFunc").mockImplementation((name, fn) => fn());

describe("test", () => {
   ...
});

I decided to keep X-Ray disabled for unit tests. Like this:

if (!process.env.IS_OFFLINE) {
  AWSXRay.captureHTTPsGlobal(require('http'));
}

It would be fantastic if the xray sdk had a global option for disabling during unit testing.

Because of this issue I gave up on using XRay. All our services are following CI/CD and if I can't test them, they can't deploy. I hope that this issue can get resolved.

Hi @manchuck,
Sorry for the delayed response, and I apologize for the frustration you're experiencing. While it does not strictly disable X-Ray, you may prevent the errors you are receiving from failing your unit tests using the ContextMissingStrategy. This can be done by setting the AWS_XRAY_CONTEXT_MISSING environment variable to LOG_ERROR. This emits a warning to the logs when the SDK encounters the error you're receiving rather than causing a runtime error. Read more about our environment variables here (but please note the log level setting feature has not been released to NPM yet).

Additionally, you can set a custom context missing strategy with a function of your own (e.g. a no-op) using this API. Sorry for the lack of formal documentation, please reach out again if you need further clarifications. It should be noted that setting the context missing environment variable will override any custom function provided programmatically.

@willarmiros I will close the issue once the documentation has been updated.

Hi @manchuck,
You can view the updated documentation here. Hope this resolves your issue!

@willarmiros Ahh so good. Closing this issue

Was this page helpful?
0 / 5 - 0 ratings