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

test: refactor to move knowledge for in-process Agent re-use into Agent methods #2305

Merged
merged 9 commits into from
Aug 31, 2021

Conversation

trentm
Copy link
Member

@trentm trentm commented Aug 26, 2021

Move away from using the test/_agent.js wrapper in tests, in favour of using the real Agent class directly and agent.destroy() at the end of a test to clean up. Agent#destroy() has been improved and Instrumentation#stop() added to properly handle agent clean-up (within reason) such that tests can serially create multiple instances of the Agent.

Agent#destroy() and Instrumentation#stop() are mostly what the "test/_agent.js" cleanup was doing with some improvements:

  • restore Error.stackTraceLimit
  • disable the running asyncHook

Not all usage of test/_agent.js has been removed -- just the major users agents.test.js and config.test.js.
I'll look at doing the others in subsequent changes. This PR is big enough already.

The motivation for this work is to help with test suite updates for the async context work. The internals of Instrumentation are changing, so it has been a pain that the test suite assumes so many internals.

@trentm trentm self-assigned this Aug 26, 2021
@github-actions github-actions bot added the agent-nodejs Make available for APM Agents project planning. label Aug 26, 2021
…nt methods

Move away from the test/_apm_server.js and test/_agent.js pattern that
encapsulates internal details of Agent and Instrumentation to allow
re-use of an Agent instance in-process in the same test file. The
pattern from these test support files also makes leftover state from a
test case an issue for *subsequent* test cases to deal with.

Instead we add agent._testReset (and ins.testReset) to encapsulate
these internal details.

This also fixes a bug in agent.test.js where a new async-hook was
being created and enabled for each Agent re-use. Cleanup was never
disabling those async-hooks.
@trentm trentm force-pushed the trentm/sans-mock-agent branch from a8d9bc7 to 9dbded4 Compare August 26, 2021 01:10
@apmmachine
Copy link
Contributor

apmmachine commented Aug 26, 2021

💚 Build Succeeded

the below badges are clickable and redirect to their specific view in the CI or DOCS
Pipeline View Test View Changes Artifacts preview preview

Expand to view the summary

Build stats

  • Start Time: 2021-08-27T00:26:16.849+0000

  • Duration: 19 min 47 sec

  • Commit: 6810173

Test stats 🧪

Test Results
Failed 0
Passed 20
Skipped 0
Total 20

Trends 🧪

Image of Build Times

Image of Tests

Copy link
Member Author

@trentm trentm left a comment

Choose a reason for hiding this comment

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

Add some reviewer notes.

@@ -22,13 +22,6 @@ if (packageName === 'elastic-apm-node') {
}
var userAgent = `${packageName}/${version}`

config.INTAKE_STRING_MAX_SIZE = 1024
Copy link
Member Author

Choose a reason for hiding this comment

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

REVIEWER NOTE: All the changes in this file were to export DEFAULTS to use in one of the tests below. Then, because the CAPTURE_... constants are used in the declaration of DEFAULTS, it was cleaner to declare the exports as consts and setup module.exports at the bottom.

if (_asyncHook) _asyncHook.disable()
_asyncHook = asyncHook
}

Copy link
Member Author

Choose a reason for hiding this comment

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

This asyncHook.disable() moved to Instrumentation#stop(), removing the need for _ELASTIC_APM_ASYNC_HOOKS_RESETTABLE.


// ---- internal support functions

function assertMetadata (t, payload) {
Copy link
Member Author

Choose a reason for hiding this comment

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

REVIEWER NOTE: These few support functions were moved up from the bottom of the file without modification. The structure of the file is now:

// imports and consts
// support functions
// tests

@trentm trentm marked this pull request as ready for review August 30, 2021 16:01
@trentm trentm requested a review from astorm August 30, 2021 16:01
Copy link
Contributor

@astorm astorm left a comment

Choose a reason for hiding this comment

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

The changes here look reasonable and seem like appropriate steps towards being able to better test changes we're making to our context handling.

Approving, pending one discretionary question.

I noticed that a run of test/agent.test.js went from 853 assertions to 572 assertions with these changes.

$ npx tape test/agent.test.js
//...
1..853
# tests 853
# pass  853

# ok

$ git checkout trentm/sans-mock-agent
$ npx tape test/agent.test.js
//...
1..572
# tests 572
# pass  572

# ok

These seemed to be from test suites that used the now removed APMServerWithDefaultAsserts function. Here's one example

Before:

# capture location stack trace - off (param msg)
ok 539 should be a POST request
ok 540 should be sent to the intake endpoint
ok 541 metadata should always be sent first
ok 542 should be strictly equal
ok 543 should be deeply equivalent
ok 544 should be deeply equivalent
ok 545 should be deeply equivalent
ok 546 should be strictly equal
ok 547 should be strictly equal
ok 548 should be strictly equal
ok 549 should be truthy
ok 550 should be strictly equal
ok 551 should have a pid greater than 0
ok 552 should have a process title
ok 553 should be strictly equal
ok 554 should be deeply equivalent
ok 555 should have at least two process arguments
ok 556 should be strictly equal
ok 557 should not have a log.stacktrace
ok 558 should not have an exception

After:

# capture location stack trace - off (param msg)
ok 384 APM server got 2 events
ok 385 should be strictly equal
ok 386 should not have a log.stacktrace
ok 387 should not have an exception

Is there any concern about this lost coverage? Or were the tests that came along with the old APMServerWithDefaultAsserts now redundant?

Agent.prototype.destroy = function () {
if (this._transport) this._transport.destroy()
if (this._transport && this._transport.destroy) {
Copy link
Contributor

Choose a reason for hiding this comment

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

👍 I did a quick scan of the work done in both the agent's constructor and agent.start() and the values reset here appear to be sufficient.

@@ -38,6 +31,11 @@ try {
serviceVersion = version
} catch (err) {}

const INTAKE_STRING_MAX_SIZE = 1024
Copy link
Contributor

Choose a reason for hiding this comment

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

👍 I generally prefer "export everything once at the bottom" approach, and I never liked relying on the config function being hoisted up

asyncHook.disable()
activeTransactions.clear()
activeSpans.clear()
contexts = new WeakMap()
Copy link
Contributor

Choose a reason for hiding this comment

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

// has no way to update existing references to patched or unpatched exports from
// those modules.
Instrumentation.prototype.stop = function () {
// Reset context tracking.
Copy link
Contributor

Choose a reason for hiding this comment

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

👍 Appears to reset the appropriate properties.

@trentm
Copy link
Member Author

trentm commented Aug 31, 2021

Is there any concern about this lost coverage? Or were the tests that came along with the old APMServerWithDefaultAsserts now redundant?

There is no concern in my humble opinion. Here is what the old test code would do for each of the 33 usages of APMServerWithDefaultAsserts:

function APMServerWithDefaultAsserts (t, agentOpts, mockOpts) {
  var server = APMServer(agentOpts, mockOpts)
    .on('request', validateRequest(t))
    .on('data-metadata', validateMetadata(t))
 // ...
}

function validateRequest (t) {
  return function (req) {
    t.strictEqual(req.method, 'POST', 'should be a POST request')
    t.strictEqual(req.url, '/intake/v2/events', 'should be sent to the intake endpoint')
  }
}

function validateMetadata (t) {
  return function (data, index) {
    t.strictEqual(index, 0, 'metadata should always be sent first')
    assertMetadata(t, data)
  }
}
  • The validateRequest asserts are redudant because the MockAPMServer being used now only captures events for tests if the request is a POST /intake/v2/events:
      } else if (req.method === 'POST' && parsedUrl.pathname === '/intake/v2/events') {
        body
          .split(/\n/g) // parse each line
          .filter(line => line.trim()) // ... if it is non-empty
          .forEach(line => {
            this.events.push(JSON.parse(line)) // ... append to this.events
          })
  • The assertMetadata is still being done, but just not for every test -- in about 12 of them instead of 33.

@astorm
Copy link
Contributor

astorm commented Aug 31, 2021

@trentm sounds good! Approved x2

@trentm trentm merged commit 986b6a4 into master Aug 31, 2021
@trentm trentm deleted the trentm/sans-mock-agent branch August 31, 2021 19:57
@trentm
Copy link
Member Author

trentm commented Aug 31, 2021

Thanks for the review!

dgieselaar pushed a commit to dgieselaar/apm-agent-nodejs that referenced this pull request Sep 10, 2021
…nt methods (elastic#2305)

Move away from using the test/_agent.js wrapper in tests, in favour of
using the real Agent class directly and agent.destroy() at the end of a
test to clean up.  Agent#destroy() has been improved and
Instrumentation#stop() added to properly handle agent clean-up (within
reason) such that tests can serially create multiple instances of the
Agent.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
agent-nodejs Make available for APM Agents project planning.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants