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

[Unified Recorder] Support "variables" in recordings with proxy-tool #18585

Merged
merged 12 commits into from
Nov 11, 2021

Conversation

HarshaNalluru
Copy link
Member

@HarshaNalluru HarshaNalluru commented Nov 9, 2021

Issue #18580

What?

Allows storing the dynamically created variables in the record mode. Recorder registers the variables as part of the recording. Using the "variables" in playback mode would give the key-value pairs that are stored in record mode.

Example:

if (!isPlaybackMode()) {
  recorder.variables["random-1"] = `random-${Math.ceil(Math.random() * 1000 + 1000)}`;
}

Use this recorder.variables["random-1"] wherever you'd like to use in your test after the if-block.
(This would work in all three modes - record/playback/live just by adding the if-block above)

Internals(How does it work?):

  • recorder.stop() call sends the variables to the proxy-tool (in record mode) to save them in recordings
  • recorder.start() call loads those variables given by the proxy tool (in playback mode) that are picked up from the recordings

Copy link
Member

@seankane-msft seankane-msft left a comment

Choose a reason for hiding this comment

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

LGTM, should probably have a JS specialist give the final approval

@HarshaNalluru HarshaNalluru mentioned this pull request Nov 9, 2021
97 tasks
@@ -181,6 +203,10 @@ export class TestProxyHttpClient {
const req = this._createRecordingRequest(stopUri);
req.headers.set("x-recording-save", "true");

if (isRecordMode()) {
req.headers.set("Content-Type", "application/json");
req.body = JSON.stringify(variables ?? this.variables);
Copy link
Contributor

Choose a reason for hiding this comment

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

Wouldn’t this mean that we’re setting req.body to undefined if there are no variables? Is that desired?

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.variables is initialized as {}.
image

So, no problem.

Copy link
Contributor

@sadasant sadasant left a comment

Choose a reason for hiding this comment

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

Looks good to me!

Copy link
Member

@witemple-msft witemple-msft left a comment

Choose a reason for hiding this comment

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

It's clever and the implementation seems very simple. Since the variables are sent as JSON, I wonder why we can't store more than just strings. For example, I might like to store a number or even a nested object.

If you're interested in that idea, we can explore how the consumers of this API can strongly type that.

sdk/test-utils/recorder-new/CHANGELOG.md Outdated Show resolved Hide resolved
sdk/test-utils/recorder-new/CHANGELOG.md Outdated Show resolved Hide resolved
@@ -151,6 +170,9 @@ export class TestProxyHttpClient {
throw new RecorderError("No recording ID returned for a successful start request.");
}
this.recordingId = id;
if (isPlaybackMode()) {
this.variables = !rsp.bodyAsText ? {} : JSON.parse(rsp.bodyAsText);
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
this.variables = !rsp.bodyAsText ? {} : JSON.parse(rsp.bodyAsText);
this.variables = JSON.parse(rsp.bodyAsText ?? "{}") as Record<string, string>;

Is the body not automatically parsed given the content type?

Copy link
Member

Choose a reason for hiding this comment

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

No, that happens in the deserializationPolicy

Copy link
Member Author

Choose a reason for hiding this comment

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

Haven't checked,

sdk/test-utils/recorder-new/src/core-v2-recorder.ts Outdated Show resolved Hide resolved
recorder.variables["random-2"] = "known-string";
}

await makeRequestAndVerifyResponse(
Copy link
Member

Choose a reason for hiding this comment

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

Could you explain what this is verifying? I see a variable is set, the variable is used in the request path, and test server seems always return "I am the answer!" but am not clear what's involved

Copy link
Member

Choose a reason for hiding this comment

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

oh, in playback mode, these variables will be available?

Copy link
Member Author

Choose a reason for hiding this comment

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

makeRequestAndVerifyResponse is a generic method and is applied for all the tests in this test suite.
It was initially created for the rest of the tests in the describe block.
All it does is make the request and check the response with what we are supposed to get.

All tests are run in the record, playback, and live modes in sequence in the same run.

The idea of the test is that the random string won't change in playback mode, and it'll reuse whatever has been created in the record mode.

Any suggestions on how I can make this clear? or improve the test?

Copy link
Member

Choose a reason for hiding this comment

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

This is fine. setting is in record mode but reading is in playback mode so I don't think there is a straight-forward way to test them as a whole. but end-to-end is working so we are good.

HarshaNalluru and others added 5 commits November 11, 2021 12:54
Co-authored-by: Will Temple <witemple@microsoft.com>
Co-authored-by: Will Temple <witemple@microsoft.com>
Co-authored-by: Will Temple <witemple@microsoft.com>
@HarshaNalluru
Copy link
Member Author

@witemple-msft

It's clever and the implementation seems very simple. Since the variables are sent as JSON, I wonder why we can't store more than just strings. For example, I might like to store a number or even a nested object.

I did try to support numbers, but proxy-tool seems to be doing some validation on its end which is failing for numbers. So, kept strings only as of now. I provided the info to Scott. We'll see once the proxy tool's support improves.

If you're interested in that idea, we can explore how the consumers of this API can strongly type that.

I was thinking in those lines but as we only support strings at the moment, not much is needed at the moment.
I'm definitely interested 💗, let's recoup once we have more support.

Tracking your comments in the epic #15829 for now.

@HarshaNalluru HarshaNalluru merged commit a5d9897 into Azure:main Nov 11, 2021
@HarshaNalluru HarshaNalluru deleted the harshan/issue/18580 branch November 11, 2021 22:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants