diff --git a/client/changelog.md b/client/changelog.md index 776f41f8..db4486fb 100644 --- a/client/changelog.md +++ b/client/changelog.md @@ -1,4 +1,7 @@ -#### 2018-09-12 1.0.1 +### 2018-09-14 1.0.2 +- `client.getPartitionInformation()` should works as expected when partitionId is of type `number | string`. + +### 2018-09-12 1.0.1 - Stable version of the libray. ### 2018-09-11 0.2.10 diff --git a/client/lib/eventHubClient.ts b/client/lib/eventHubClient.ts index 3c3979d7..2975b24c 100644 --- a/client/lib/eventHubClient.ts +++ b/client/lib/eventHubClient.ts @@ -281,7 +281,7 @@ export class EventHubClient { * @returns {Promise} A promise that resoloves with EventHubPartitionRuntimeInformation. */ async getPartitionInformation(partitionId: string | number): Promise { - if (!partitionId || (partitionId && typeof partitionId !== "string" && typeof partitionId !== "number")) { + if (typeof partitionId !== "string" && typeof partitionId !== "number") { throw new Error("'partitionId' is a required parameter and must be of type: 'string' | 'number'."); } try { diff --git a/client/lib/managementClient.ts b/client/lib/managementClient.ts index fcf23cc6..b7adba63 100644 --- a/client/lib/managementClient.ts +++ b/client/lib/managementClient.ts @@ -157,8 +157,7 @@ export class ManagementClient extends LinkEntity { * @param {(string|number)} partitionId Partition ID for which partition information is required. */ async getPartitionInformation(partitionId: string | number): Promise { - if (!partitionId || - (partitionId && typeof partitionId !== "string" && typeof partitionId !== "number")) { + if (typeof partitionId !== "string" && typeof partitionId !== "number") { throw new Error("'partitionId' is a required parameter and must be of " + "type: 'string' | 'number'."); } @@ -249,7 +248,7 @@ export class ManagementClient extends LinkEntity { * @param {string | number} [partitionId] - The partitionId. Required only when type is "partition". */ private async _makeManagementRequest(type: "eventhub" | "partition", partitionId?: string | number): Promise { - if (partitionId && typeof partitionId !== "string" && typeof partitionId !== "number") { + if (partitionId != undefined && (typeof partitionId !== "string" && typeof partitionId !== "number")) { throw new Error("'partitionId' is a required parameter and must be of type: 'string' | 'number'."); } try { @@ -263,8 +262,8 @@ export class ManagementClient extends LinkEntity { type: `${Constants.vendorString}:${type}` } }; - if (partitionId && type === Constants.partition) { - request.application_properties!.partition = partitionId; + if (partitionId != undefined && type === Constants.partition) { + request.application_properties!.partition = `${partitionId}`; } log.mgmt("[%s] Acquiring lock to get the management req res link.", this._context.connectionId); await defaultLock.acquire(this.managementLock, () => { return this._init(); }); diff --git a/client/package-lock.json b/client/package-lock.json index c15ab7fa..17acb89c 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -1,6 +1,6 @@ { "name": "@azure/event-hubs", - "version": "1.0.1", + "version": "1.0.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/client/package.json b/client/package.json index aebe615b..3f88c4ee 100644 --- a/client/package.json +++ b/client/package.json @@ -1,6 +1,6 @@ { "name": "@azure/event-hubs", - "version": "1.0.1", + "version": "1.0.2", "description": "Azure Event Hubs SDK for JS.", "author": "Microsoft Corporation", "license": "MIT", diff --git a/client/tests/hubruntime.spec.ts b/client/tests/hubruntime.spec.ts index d93290cf..97bddb15 100644 --- a/client/tests/hubruntime.spec.ts +++ b/client/tests/hubruntime.spec.ts @@ -44,7 +44,7 @@ describe("RuntimeInformation", function () { hubRuntimeInfo.createdAt.should.be.instanceof(Date); }); - it("gets the partition runtime information", async function () { + it("gets the partition runtime information with partitionId as a string", async function () { client = EventHubClient.createFromConnectionString(service.connectionString!, service.path); const partitionRuntimeInfo = await client.getPartitionInformation("0"); debug(partitionRuntimeInfo); @@ -55,4 +55,43 @@ describe("RuntimeInformation", function () { should.exist(partitionRuntimeInfo.lastSequenceNumber); should.exist(partitionRuntimeInfo.lastEnqueuedOffset); }); + + it("gets the partition runtime information with partitionId as a number", async function () { + client = EventHubClient.createFromConnectionString(service.connectionString!, service.path); + const partitionRuntimeInfo = await client.getPartitionInformation(0); + debug(partitionRuntimeInfo); + partitionRuntimeInfo.partitionId.should.equal("0"); + partitionRuntimeInfo.type.should.equal("com.microsoft:partition"); + partitionRuntimeInfo.hubPath.should.equal(service.path); + partitionRuntimeInfo.lastEnqueuedTimeUtc.should.be.instanceof(Date); + should.exist(partitionRuntimeInfo.lastSequenceNumber); + should.exist(partitionRuntimeInfo.lastEnqueuedOffset); + }); + + it("should fail the partition runtime information when partitionId is not a number or string", async function () { + client = EventHubClient.createFromConnectionString(service.connectionString!, service.path); + try { + const partitionRuntimeInfo = await client.getPartitionInformation(true as any); + } catch (err) { + err.message.should.equal("'partitionId' is a required parameter and must be of type: 'string' | 'number'."); + } + }); + + it("should fail the partition runtime information when partitionId is empty string", async function () { + client = EventHubClient.createFromConnectionString(service.connectionString!, service.path); + try { + const partitionRuntimeInfo = await client.getPartitionInformation(""); + } catch (err) { + err.message.should.match(/.*The specified partition is invalid for an EventHub partition sender or receiver.*/ig); + } + }); + + it("should fail the partition runtime information when partitionId is a negative number", async function () { + client = EventHubClient.createFromConnectionString(service.connectionString!, service.path); + try { + const partitionRuntimeInfo = await client.getPartitionInformation(-1); + } catch (err) { + err.message.should.match(/.*The specified partition is invalid for an EventHub partition sender or receiver.*/ig); + } + }); }); \ No newline at end of file diff --git a/processor/changelog.md b/processor/changelog.md index c93cb16e..8657e856 100644 --- a/processor/changelog.md +++ b/processor/changelog.md @@ -1,3 +1,7 @@ +### 2018-09-14 1.0.1 +- `eph.getPartitionInformation()` should works as expected when partitionId is of type `number | string`. +- updated documentation for `eventHubPath` optional property in the `FromConnectionStringOptions` object. + ## 2018-09-12 1.0.0 - Stable version of the library. diff --git a/processor/lib/hostContext.ts b/processor/lib/hostContext.ts index 93b6cdca..a1635140 100644 --- a/processor/lib/hostContext.ts +++ b/processor/lib/hostContext.ts @@ -144,9 +144,11 @@ export namespace HostContext { const onEphErrorFunc: OnEphError = () => { // do nothing }; + const config = ConnectionConfig.create(options.eventHubConnectionString!, options.eventHubPath); // set defaults if (!options.consumerGroup) options.consumerGroup = defaultConsumerGroup; + if (!options.eventHubPath) options.eventHubPath = config.entityPath; if (!options.leaseRenewInterval) options.leaseRenewInterval = defaultLeaseRenewIntervalInSeconds; if (!options.leaseDuration) options.leaseDuration = defaultLeaseDurationInSeconds; if (!options.onEphError) options.onEphError = onEphErrorFunc; @@ -169,7 +171,7 @@ export namespace HostContext { _eitherStorageConnectionStringOrCheckpointLeaseManager(options); _eitherLeaseManagerOrleaseDurationAndRenewal(options); - const config = ConnectionConfig.create(options.eventHubConnectionString!, options.eventHubPath); + const context: BaseHostContext = { hostName: hostName, eventHubConnectionString: options.eventHubConnectionString!, @@ -238,7 +240,7 @@ export namespace HostContext { client.close().catch(/* do nothing */); return result; }; - ctxt.getPartitionInformation = async (id: string) => { + ctxt.getPartitionInformation = async (id: string | number) => { const client = ctxt.getEventHubClient(); const result = await client.getPartitionInformation(id); client.close().catch(/* do nothing */); diff --git a/processor/lib/modelTypes.ts b/processor/lib/modelTypes.ts index 6e1b0223..3ec7f103 100644 --- a/processor/lib/modelTypes.ts +++ b/processor/lib/modelTypes.ts @@ -151,7 +151,7 @@ export interface FromTokenProviderOptions extends ClientOptionsBase { export interface FromConnectionStringOptions extends FromTokenProviderOptions { /** * @property {string} [eventHubPath] The name of the EventHub. This is optional if the - * EventHub connection string contains ENTITY_PATH=hub-name else an Error will be thrown. + * EventHub connection string contains EntityPath=hub-name else an Error will be thrown. */ eventHubPath?: string; } diff --git a/processor/package.json b/processor/package.json index 6e64bc71..0b2fd344 100644 --- a/processor/package.json +++ b/processor/package.json @@ -1,13 +1,13 @@ { "name": "@azure/event-processor-host", - "version": "1.0.0", + "version": "1.0.1", "description": "Azure Event Processor Host (Event Hubs) SDK for JS.", "author": "Microsoft Corporation", "license": "MIT", "main": "./dist/lib/index.js", "types": "./typings/lib/index.d.ts", "dependencies": { - "@azure/event-hubs": "^1.0.1", + "@azure/event-hubs": "^1.0.2", "azure-storage": "^2.10.1", "debug": "^3.1.0", "ms-rest-azure": "^2.5.7", @@ -48,4 +48,4 @@ "bugs": { "url": "http://github.com/Azure/azure-event-hubs-node/issues" } -} +} \ No newline at end of file diff --git a/processor/tests/eph.spec.ts b/processor/tests/eph.spec.ts index b894f81d..2b3dae72 100644 --- a/processor/tests/eph.spec.ts +++ b/processor/tests/eph.spec.ts @@ -299,4 +299,170 @@ describe("EPH", function () { } }); }); + + describe("runtimeInfo", function () { + it("should get hub runtime info correctly", async function () { + host = EventProcessorHost.createFromConnectionString( + EventProcessorHost.createHostName(), + storageConnString!, + EventProcessorHost.createHostName("single"), + ehConnString!, + { + eventHubPath: hubName!, + initialOffset: EventPosition.fromEnqueuedTime(Date.now()) + } + ); + const hubRuntimeInfo = await host.getHubRuntimeInformation(); + should.equal(Array.isArray(hubRuntimeInfo.partitionIds), true); + should.equal(typeof hubRuntimeInfo.partitionCount, "number"); + }); + + it("should get partition runtime info correctly with partitionId as string", async function () { + host = EventProcessorHost.createFromConnectionString( + EventProcessorHost.createHostName(), + storageConnString!, + EventProcessorHost.createHostName("single"), + ehConnString!, + { + eventHubPath: hubName!, + initialOffset: EventPosition.fromEnqueuedTime(Date.now()) + } + ); + const partitionInfo = await host.getPartitionInformation("0"); + debug(">>> partitionInfo: %o", partitionInfo); + partitionInfo.partitionId.should.equal("0"); + partitionInfo.type.should.equal("com.microsoft:partition"); + partitionInfo.hubPath.should.equal(hubName); + partitionInfo.lastEnqueuedTimeUtc.should.be.instanceof(Date); + should.exist(partitionInfo.lastSequenceNumber); + should.exist(partitionInfo.lastEnqueuedOffset); + }); + + it("should get partition runtime info correctly with partitionId as number", async function () { + host = EventProcessorHost.createFromConnectionString( + EventProcessorHost.createHostName(), + storageConnString!, + EventProcessorHost.createHostName("single"), + ehConnString!, + { + eventHubPath: hubName!, + initialOffset: EventPosition.fromEnqueuedTime(Date.now()) + } + ); + const partitionInfo = await host.getPartitionInformation(0); + partitionInfo.partitionId.should.equal("0"); + partitionInfo.type.should.equal("com.microsoft:partition"); + partitionInfo.hubPath.should.equal(hubName); + partitionInfo.lastEnqueuedTimeUtc.should.be.instanceof(Date); + should.exist(partitionInfo.lastSequenceNumber); + should.exist(partitionInfo.lastEnqueuedOffset); + }); + + it("should fail getting partition information when partitionId is not a string or number", async function () { + host = EventProcessorHost.createFromConnectionString( + EventProcessorHost.createHostName(), + storageConnString!, + EventProcessorHost.createHostName("single"), + ehConnString!, + { + eventHubPath: hubName!, + initialOffset: EventPosition.fromEnqueuedTime(Date.now()) + } + ); + try { + await host.getPartitionInformation(false as any); + } catch (err) { + err.message.should.equal("'partitionId' is a required parameter and must be of type: 'string' | 'number'."); + } + }); + + it("should fail getting partition information when partitionId is empty string", async function () { + host = EventProcessorHost.createFromConnectionString( + EventProcessorHost.createHostName(), + storageConnString!, + EventProcessorHost.createHostName("single"), + ehConnString!, + { + eventHubPath: hubName!, + initialOffset: EventPosition.fromEnqueuedTime(Date.now()) + } + ); + try { + await host.getPartitionInformation(""); + } catch (err) { + err.message.should.match(/.*The specified partition is invalid for an EventHub partition sender or receiver.*/ig); + } + }); + + it("should fail getting partition information when partitionId is a negative number", async function () { + host = EventProcessorHost.createFromConnectionString( + EventProcessorHost.createHostName(), + storageConnString!, + EventProcessorHost.createHostName("single"), + ehConnString!, + { + eventHubPath: hubName!, + initialOffset: EventPosition.fromEnqueuedTime(Date.now()) + } + ); + try { + await host.getPartitionInformation(-1); + } catch (err) { + err.message.should.match(/.*The specified partition is invalid for an EventHub partition sender or receiver.*/ig); + } + }); + }); + + describe("options", function () { + it("should throw an error if the event hub name is neither provided in the connection string and nor in the options object", function () { + try { + const ehc = "Endpoint=sb://foo.bar.baz.net/;SharedAccessKeyName=somekey;SharedAccessKey=somesecret" + EventProcessorHost.createFromConnectionString( + EventProcessorHost.createHostName(), + storageConnString!, + EventProcessorHost.createHostName("single"), + ehc, + { + initialOffset: EventPosition.fromEnqueuedTime(Date.now()) + } + ); + } catch (err) { + should.exist(err); + err.message.match(/.*Either provide "path" or the "connectionString": "Endpoint=sb:\/\/foo\.bar\.baz\.net\/;SharedAccessKeyName=somekey;SharedAccessKey=somesecret", must contain EntityPath=".*"/ig); + } + }); + + it("should get hub runtime info correctly when eventhub name is present in connection string but not as an option in the options object.", async function () { + host = EventProcessorHost.createFromConnectionString( + EventProcessorHost.createHostName(), + storageConnString!, + EventProcessorHost.createHostName("single"), + `${ehConnString!};EntityPath=${hubName!}`, + { + initialOffset: EventPosition.fromEnqueuedTime(Date.now()) + } + ); + const hubRuntimeInfo = await host.getHubRuntimeInformation(); + hubRuntimeInfo.path.should.equal(hubName); + should.equal(Array.isArray(hubRuntimeInfo.partitionIds), true); + should.equal(typeof hubRuntimeInfo.partitionCount, "number"); + }); + + it("when eventhub name is present in connection string and in the options object, the one in options object is selected.", async function () { + host = EventProcessorHost.createFromConnectionString( + EventProcessorHost.createHostName(), + storageConnString!, + EventProcessorHost.createHostName("single"), + `${ehConnString!};EntityPath=foo`, + { + eventHubPath: hubName, + initialOffset: EventPosition.fromEnqueuedTime(Date.now()) + } + ); + const hubRuntimeInfo = await host.getHubRuntimeInformation(); + hubRuntimeInfo.path.should.equal(hubName); + should.equal(Array.isArray(hubRuntimeInfo.partitionIds), true); + should.equal(typeof hubRuntimeInfo.partitionCount, "number"); + }); + }); }); \ No newline at end of file