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

[Service Bus] Update constructors to add overloads and use Azure Identity #5436

Merged
merged 25 commits into from
Jan 15, 2020

Conversation

ramya0820
Copy link
Member

@ramya0820 ramya0820 commented Oct 7, 2019

For more context refer to #4262

Verified build and local smoke test run of live tests

@ramya-rao-a
Copy link
Contributor

I'll hold back on reviewing this PR until we rebase/merge from master after #5324 gets merged

@ramya0820 ramya0820 changed the base branch from master to feature/service-bus-track-2 January 2, 2020 19:11
@ramya0820
Copy link
Member Author

Updated PR with changes from #5324 - verified that build and tests are running fine on local. @ramya-rao-a @chradek

Copy link
Contributor

@ramya-rao-a ramya-rao-a left a comment

Choose a reason for hiding this comment

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

In Track2, we do not want to expose SharedKeyCredential and ConnectionConfig from our client constructors. Use the EventHubProducerClient constructor overloads in the Event Hubs library as reference if needed.

@ramya0820
Copy link
Member Author

In Track2, we do not want to expose SharedKeyCredential and ConnectionConfig from our client constructors. Use the EventHubProducerClient constructor overloads in the Event Hubs library as reference if needed.

Updated PR
Looks like the way we construct ConnectionCOnfig internally is by manually constructing the connection string.
This seems specific to Event Hubs and unsure if the same approach can be used for SB.

@ramya0820 ramya0820 requested a review from bterlson as a code owner January 3, 2020 22:33
@ramya-rao-a
Copy link
Contributor

There was a test for custom token provider which was commented in the track 2 branch because the createFromTokenProvider was commented in this branch.

Now that we have the constructor overload that can take a custom token provider (i.e a custom TokenCredential), we should re-enable the above test as well.

Copy link
Contributor

@ramya-rao-a ramya-rao-a left a comment

Choose a reason for hiding this comment

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

Few pending items other than the ongoing discussion on the constructor overloads:

@ramya0820
Copy link
Member Author

Had a question on about which TokenCredential to use in place of the SasTokenProvider from amqp-common that was being used previously. https://github.com/Azure/azure-sdk-for-js/pull/6770/files#r366494233 @ramya-rao-a

@@ -150,8 +150,9 @@ export class Sender {

// @public
export class ServiceBusClient {
constructor(connectionString: string, options?: ServiceBusClientOptions);
constructor(credential: TokenCredential, host: string, options?: ServiceBusClientOptions);
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the ordering of parameters here should be switched for consistency with event hubs.

constructor(host: string, credential: TokenCredential, options?: ServiceBusClientOptions);

This also matches the sample in the typescript design guidelines.

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh, could you point to which guideline is being considered for this?

Because I found the following that seems similar / applicable for hostOrConnectionString usage

// bad example
class ExampleClient {
  constructor (connectionString: string, options: ExampleClientOptions);
  constructor (url: string, options: ExampleClientOptions);
  constructor (urlOrCS: string, options: ExampleClientOptions) {
    // have to dig into the first parameter to see whether its
    // a url or a connection string. Not ideal.
  }
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Link was hidden in the word 'guidelines' :)
https://azure.github.io/azure-sdk/typescript_design.html#ts-apisurface-serviceclient

See the Client API example.

// client constructors have overloads for handling different
// authentication schemes.
constructor(connectionString: string, options?: ServiceClientOptions);
constructor(host: string, credential: TokenCredential, options?: ServiceClientOptions);

Copy link
Contributor

Choose a reason for hiding this comment

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

The reason the example you posted is considered bad is because the type signatures for both constructors are exactly the same (string, options). In our case though we have 2 unique signatures (string, options) and (string, TokenCredential, options)

Copy link
Member Author

Choose a reason for hiding this comment

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

Unable to reply to other comment for some reason :?
Yes, EventHubs impl seems to have the different concerns addressed. The type of error being thrown is useful to note as well (TypeError as opposed to simple Error)
I just have the guideline aspect clarification pending - ok to be consistent with EventHubs if that's what we want to do
Thoughts? @ramya-rao-a @bterlson

Personally, I think the example called out on the guidelines page resonates with my initial thoughts on switching the parameters - also because credential based constructor sounded more right too, than host based. (Going by the first parameter to pass in).

Copy link
Member Author

Choose a reason for hiding this comment

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

Ok, the other observation I had was that options parameter being optional - seemed out of place to rely on type of to decide which constructor to use at first. So without that it can come down to two parameter constructor :?

Like, JS in general isn't strict on parameter numbers to be passed in.
So I think the one usecase that I had brought up earlier and seems to not be handled by EventHubs is if user invokes the host and credential based constructor as
(hostName, undefined, options) - then it looks like the error user would get would be about having to pass in a correctly formatted connection string.

Copy link
Member Author

Choose a reason for hiding this comment

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

To summarize the thread here - the user experience for when credential is passed in as undefined is the one that seems unaddressed.

Let's take a call on if we want to address that as a bug and fix it here or not - and if we want to still go ahead with mirroring EventHubs constructors for most part.

cc @ramya-rao-a @chradek
@bterlson @AlexGhiondea

Copy link
Contributor

Choose a reason for hiding this comment

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

The situation where a user passed undefined for the credential but still passes the options after it seems very unlikely. I think you could make the argument that if they're explicitly trying to not pass in a TokenCredential, then they would want a connection string (so the error seems relevant). But, I don't feel too strongly since they would be going against the types and docs in this case (I'm glad we give some error).

With regards to the parameter order for the constructors, my vote is for consistency. Since event-hubs is already GA, changing the order there would need a major version bump. I see one of our goals as providing a consistent experience across the packages we own (when possible) to lower the learning curve for users going from one package to another.

Copy link
Member Author

@ramya0820 ramya0820 Jan 14, 2020

Choose a reason for hiding this comment

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

Fair point, updated parameters ordering to keep up with consistency as if we decide to change, we can do it together

Agree that explicitly passing in undefined would map more to connection string based constructor.
But if say a user is instantiating the credentials programmatically, they could run into an undefined object.
Event Hubs seems a bit different in that it accepts event hub name in addition to connection string in Event Hubs SDK. So it seems a little more relevant to Event Hubs as the err msg can be confusing to troubleshoot. (Also I wonder how long it might be before we bump version, maybe that would happen at same time as when Track 2 SB would go GA, but I digress :) )

And.. if we are of pinion that this a not so ideal state afterall, then we could have not so ideal string processing to guard against the missing/undefined token credentials case in Service Bus possibly. Let me know. For now haven't included those checks since we didn't want those. @ramya-rao-a Ok if we choose to handle it all together later as well or file a new issue?
Because it seems like we might be regressing from Track 1 if we are no longer able to surface the error we used to be able to - "'credentials' is a required parameter and must be an instance of ...

let isConnectionStringConstructorInvoked = true;
if (hostOrConnectionString.indexOf("=") < 0) {
isConnectionStringConstructorInvoked = false;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm just catching up here and I might have missed some things as changes have been made.
1st, I remarked on this in the API file but I do think we want to keep connectionString and host as the first parameter in their respective constructors to be consistent with our other SDKs/guidelines.

I think the original comment was about the checks being done on hostOrConnectionString.

if (
      hostOrConnectionString == undefined ||
      hostOrConnectionString.toString == undefined ||
      hostOrConnectionString.toString().trim() == ""
    ) {
      throw new Error(
        "Input parameter of host or connection string must be defined and coercible to string."
      );
    }

I think @ramya-rao-a 's had 2 points:

  1. We can ensure hostOrConnectionString is a string by wrapping it in String: String(hostOrConnectionString)
    Note that this is different from new String(hostOrConnectionString), which is not what you want (and what I think @bterlson would warn to stay away from).
  2. There are other places where hostOrConnectionString is validated so this check isn't needed.

The EventHubClient constructor shows both of these aspects off (only linking to one line here but look at the rest of the function): https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/eventhub/event-hubs/src/impl/eventHubClient.ts#L339

Event Hubs is a bit more complicated since it has 3 overloads instead of 2, so service bus would be even simpler.

I think the Event Hubs constructor would throw helpful errors for the cases that were being checked before, but if there's something being missed let me know!

should.equal(errorWasThrown, true, "Error thrown flag must be true");
});

if (isNode) {
Copy link
Contributor

@ramya-rao-a ramya-rao-a Jan 15, 2020

Choose a reason for hiding this comment

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

What is the reason for the isNode check here?

Copy link
Member Author

Choose a reason for hiding this comment

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

That's because EnvironmentCredential is not supported in browser, so only a select subset of tests can be run in browser mode.

Carrying forward Q I had from other somewhat related comment - is SharedKeyCredential not going to be used and be removed from core-amqp? If not, was it supposed to work in browser?

Copy link
Contributor

Choose a reason for hiding this comment

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

Regarding the question on SharedKeyCredential, see #6770 (comment)

Looks like among all the credentials from azure/identity, only the interactive credential works in browser which of course we can't use in CI.

There is ongoing work to change that. For now, I believe all libraries using azure/identity are falling under this case where the credentials from the azure/identity library are not testable in browser in CI.

Copy link
Contributor

@ramya-rao-a ramya-rao-a 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. Pending items:

@ramya0820
Copy link
Member Author

/azp run js - servicebus - tests

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@@ -92,7 +92,7 @@ export class BatchingReceiver extends MessageReceiver {
const sessionError = context.session && context.session.error;
let error: Error | MessagingError;
if (sessionError) {
error = translate(sessionError);
error = translate(sessionError) as MessagingError;
Copy link
Contributor

Choose a reason for hiding this comment

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

This casting is not required. Same for a few lines below.

@@ -2,7 +2,9 @@

- Run `npm i` to install all the dependencies of this project. This is a one time task.
- The tests expect a series of queues, topics and subscriptions to exist in a single Service Bus instance.
Copy link
Contributor

Choose a reason for hiding this comment

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

After merging the feature/service-bus-atom branch, all tests now create the entities they need. So the above statement is no longer true.

Suggested change
- The tests expect a series of queues, topics and subscriptions to exist in a single Service Bus instance.
- The tests will create the required queue, topic and subscription in the Service Bus namespace you provide using environment variables.

The connection string for the service bus should be in the environment variable `SERVICEBUS_CONNECTION_STRING`.
For Node environment, the connection string for the service bus should be in the environment variable `SERVICEBUS_CONNECTION_STRING`.

For browser environment, the connection string for the service bus should be in the environment variable `SERVICEBUS_CONNECTION_STRING_BROWSER`.

Note that the tests will empty the messages in these entities to get a clean start before running each test.
Copy link
Contributor

@ramya-rao-a ramya-rao-a Jan 15, 2020

Choose a reason for hiding this comment

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

After merging the feature/service-bus-atom branch, all tests now create the entities they need. So this note and the table following it can be removed.

Similarly the sample content for the .env file should be cleaned up as well

@@ -93,6 +92,7 @@
},
"devDependencies": {
"@azure/eslint-plugin-azure-sdk": "^2.0.1",
"@azure/ms-rest-nodeauth": "^0.9.2",
Copy link
Contributor

Choose a reason for hiding this comment

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

Now that aadutils.ts file is deleted, we don't need @azure/ms-rest-nodeauth in tests either right?

Copy link
Member Author

Choose a reason for hiding this comment

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

agree, updated

@ramya-rao-a
Copy link
Contributor

On second thoughts, the changes done to the readme file for test in this PR other than the ones related to changing AAD-* to AZURE-*, should be done in the master branch.

@ramya0820
Copy link
Member Author

Agree on README related changes to be on master. Have opened #6974 and addressed the comments and more changes on there.

@ramya0820 ramya0820 merged commit 6947606 into Azure:feature/service-bus-track-2 Jan 15, 2020
HarshaNalluru added a commit that referenced this pull request Feb 12, 2020
* Pin core-amqp version to preview.1

* Update lock file

* Fix merge conflicts

* [Service Bus] Update to use core-amqp (#5324)

* Use core-amqp in atom management client, comment tests that use token provider

* [Service Bus] Update to use latest core-amqp (#6861)

* [Service Bus] Update constructors to add overloads and use Azure Identity (#5436)

* sync-versions: rhea-promise and @azure/core-amqp for service-bus

* resolve merge conflicts appropriately

* API Report File for "@Azure/service-bus"

* Address feedback

* SERVICEBUS_CONNECTION_STRING_BROWSER remove from karma.conf

* update pnpm-lock file

* update API Report File for "@Azure/service-bus"

* remove rhea and rhea-promise dependencies

* add "rhea-promise" back

Co-authored-by: Ramya Rao <[email protected]>
Co-authored-by: ramya0820 <[email protected]>
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.

4 participants