Repository: Azure/azure-functions-durable-js (ts)

Issue:
Incorrect ReturnType of `DurableOrchestrationClient.getStatus`
**Describe the bug**
`DurableOrchestrationClient` interface states that `getStatus()` returns `Promise<DurableOrchestrationStatus>`. This is correct for instances that exist and weren't purged. But for purged instances `getStatus()` returns an empty string. This is highly unexpected and should be fixed.

**Investigative information**

- Durable Functions extension version: 4.0.5030
- durable-functions npm module version: 1.5.4
- Language (JavaScript/TypeScript) and version: 4.8.4 (Typescript)
- Node.js version: 16.15.1

**To Reproduce**
Steps to reproduce the behavior:

```javascript
const client = getClient(context);
const instanceId = await client.startNew("MY_ORCHESTRATOR");

await client.getStatus(instanceId) // -> returns DurableOrchestrationStatus object

await client.purgeInstanceHistory(instanceId)
await client.getStatus(instanceId) // -> returns ""
```

**Expected behavior**
Interface of `DurableOrchestrationClient.getStatus()` represents the actual ReturnType of the method.



Pull request:
Update `client.getStatus` to be more consistent with type contract and more type-safe
Resolves #486 , see issue for more details. In addition to the issue outlined in #486, this PR also updates the behavior of `client.getStatus()` as follows:

| **Scenario** | **Old behavior** | **New behavior** |
| -------------- | -------------------| ----------------------|
| Happy scenario: extension responds with 200 or 202, but the timestamps are strings |  Object is passed as-is to the customer, with timestamps as stings, breaking type contract | User is passed a valid `DurableOrchestrationStatus` object with timestamps as `Date` objects |
| Invalid or not found `instanceId`, extension responds with 404 and empty body | User is passed an empty string, breaking type contract (#486) | Exception is thrown |
| Extension encounters an unhandled exception, responds with 500 | User is passed the response body containing exception information as the status object, breaking type contract | Exception is thrown | 
| Extension responds with valid response code, but some fields are missing (e.g., missing `name` property) | Object is passed as-is to the user, breaking type contract | Exception is thrown |
| Extension responds with valid response code, but empty response body | User is passed an empty string, breaking type contract | Exception is thrown |

In addition to these behavior changes, this PR also:

* Updates the comments on the `getStatus()` method to accurately represent what each status code means:
    - 200: completed, failed, or terminated
    - 202: pending or running
    - 404: `instanceId` not found
    - 500: exception while the extension was processing the request
* Removes the `TODO` flag in `getStatus()` unit tests, and replaces it with unit tests to test every response code, as above
* Adds unit tests to test all scenarios in the table above

P.S.: This is a breaking change

Patch:
diff --git a/src/durableorchestrationclient.ts b/src/durableorchestrationclient.ts
index 720e015..e97aafb 100644
--- a/src/durableorchestrationclient.ts
+++ b/src/durableorchestrationclient.ts
@@ -193,15 +193,35 @@ export class DurableOrchestrationClient implements DurableClient {
             instanceId,
             ...options,
         };
-        const response = await this.getStatusInternal(internalOptions);
+        const response: AxiosResponse = await this.getStatusInternal(internalOptions);
 
         switch (response.status) {
-            case 200: // instance completed
-            case 202: // instance in progress
-            case 400: // instance failed or terminated
-            case 404: // instance not found or pending
-            case 500: // instance failed with unhandled exception
-                return response.data as DurableOrchestrationStatus;
+            case 200: // instance completed, failed or terminated
+            case 202: // instance running or pending
+            case 400:
+                if (!response.data) {
+                    throw new Error(
+                        `DurableClient error: the Durable Functions extension replied with an empty HTTP ${response.status} response.`
+                    );
+                }
+
+                try {
+                    return new DurableOrchestrationStatus(response.data);
+                } catch (error) {
+                    throw new Error(
+                        `DurableClient error: could not construct a DurableOrchestrationStatus object using the data received from the Durable Functions extension: ${error.message}`
+                    );
+                }
+
+            case 404: // instance not found
+                let msg =
+                    `DurableClient error: Durable Functions extension replied with HTTP 404 response. ` +
+                    `This usually means we could not find any data associated with the instanceId provided: ${instanceId}.`;
+                if (response.data) {
+                    msg += ` Details: ${JSON.stringify(response.data)}`;
+                }
+                throw new Error(msg);
+            case 500: // request failed with unhandled exception (response data contains exception details)
             default:
                 return Promise.reject(this.createGenericError(response));
         }
diff --git a/src/durableorchestrationstatus.ts b/src/durableorchestrationstatus.ts
index ff11f48..1bf2b3b 100644
--- a/src/durableorchestrationstatus.ts
+++ b/src/durableorchestrationstatus.ts
@@ -2,16 +2,61 @@ import { OrchestrationRuntimeStatus } from "./classes";
 import * as types from "durable-functions";
 
 export class DurableOrchestrationStatus implements types.DurableOrchestrationStatus {
+    public readonly name: string;
+    public readonly instanceId: string;
+    public readonly createdTime: Date;
+    public readonly lastUpdatedTime: Date;
+    public readonly input: unknown;
+    public readonly output: unknown;
+    public readonly runtimeStatus: OrchestrationRuntimeStatus;
+    public readonly customStatus?: unknown;
+    public readonly history?: Array<unknown>;
+
     /** @hidden */
-    constructor(
-        public readonly name: string,
-        public readonly instanceId: string,
-        public readonly createdTime: Date,
-        public readonly lastUpdatedTime: Date,
-        public readonly input: unknown,
-        public readonly output: unknown,
-        public readonly runtimeStatus: OrchestrationRuntimeStatus,
-        public readonly customStatus?: unknown,
-        public readonly history?: Array<unknown>
-    ) {}
+    constructor(init: unknown) {
+        if (!this.isDurableOrchestrationStatusInit(init)) {
+            throw new TypeError(
+                `Failed to construct a DurableOrchestrationStatus object because the initializer had invalid types or missing fields. Initializer received: ${JSON.stringify(
+                    init
+                )}`
+            );
+        }
+
+        this.name = init.name;
+        this.instanceId = init.instanceId;
+        this.createdTime = new Date(init.createdTime);
+        this.lastUpdatedTime = new Date(init.lastUpdatedTime);
+        this.input = init.input;
+        this.output = init.output;
+        this.runtimeStatus = init.runtimeStatus as OrchestrationRuntimeStatus;
+        this.customStatus = init.customStatus;
+        this.history = init.history;
+    }
+
+    private isDurableOrchestrationStatusInit(obj: unknown): obj is DurableOrchestrationStatusInit {
+        const objAsInit = obj as DurableOrchestrationStatusInit;
+        return (
+            objAsInit !== undefined &&
+            typeof objAsInit.name === "string" &&
+            typeof objAsInit.instanceId === "string" &&
+            (typeof objAsInit.createdTime === "string" || objAsInit.createdTime instanceof Date) &&
+            (typeof objAsInit.lastUpdatedTime === "string" ||
+                objAsInit.lastUpdatedTime instanceof Date) &&
+            objAsInit.input !== undefined &&
+            objAsInit.output !== undefined &&
+            typeof objAsInit.runtimeStatus === "string"
+        );
+    }
+}
+
+interface DurableOrchestrationStatusInit {
+    name: string;
+    instanceId: string;
+    createdTime: string | Date;
+    lastUpdatedTime: string | Date;
+    input: unknown;
+    output: unknown;
+    runtimeStatus: string;
+    customStatus?: unknown;
+    history?: Array<unknown>;
 }


Test patch:
diff --git a/test/unit/durableclient-spec.ts b/test/unit/durableclient-spec.ts
index 876af63..62b5241 100644
--- a/test/unit/durableclient-spec.ts
+++ b/test/unit/durableclient-spec.ts
@@ -178,6 +178,10 @@ describe("Durable client RPC endpoint", () => {
             const expectedUrl = new URL(`${testRpcOrigin}/durabletask/instances/${instanceId}`);
 
             const scope = nock(expectedUrl.origin).get(expectedUrl.pathname).reply(202, {
+                name: "testOrchestration",
+                instanceId: "testInstanceId",
+                input: null,
+                output: null,
                 createdTime: "2020-01-01T05:00:00Z",
                 lastUpdatedTime: "2020-01-01T05:00:00Z",
                 runtimeStatus: "Running",
@@ -204,6 +208,10 @@ describe("Durable client RPC endpoint", () => {
                     showHistoryOutput: true,
                 })
                 .reply(202, {
+                    name: "testOrchestration",
+                    instanceId: "testInstanceId",
+                    input: null,
+                    output: null,
                     createdTime: "2020-01-01T05:00:00Z",
                     lastUpdatedTime: "2020-01-01T05:00:00Z",
                     runtimeStatus: "Pending",
@@ -265,15 +273,15 @@ describe("Durable client RPC endpoint", () => {
 
             // create dummy orchestration status for response
             const dummyDate = new Date();
-            const dummyStatus = new DurableOrchestrationStatus(
-                "dummyOrchestrationStatus",
-                "123456",
-                dummyDate,
-                dummyDate,
-                "myInput",
-                "myOutput",
-                OrchestrationRuntimeStatus.Completed
-            );
+            const dummyStatus = new DurableOrchestrationStatus({
+                name: "dummyOrchestrationStatus",
+                instanceId: "123456",
+                createdTime: dummyDate,
+                lastUpdatedTime: dummyDate,
+                input: "myInput",
+                output: "myOutput",
+                runtimeStatus: OrchestrationRuntimeStatus.Completed,
+            });
             const dummyStatusJSON = JSON.stringify(dummyStatus);
 
             const scopeWithTokenResponse = nock(expectedUrl.origin)
diff --git a/test/unit/orchestrationclient-spec.ts b/test/unit/orchestrationclient-spec.ts
index b196323..0ebf21f 100644
--- a/test/unit/orchestrationclient-spec.ts
+++ b/test/unit/orchestrationclient-spec.ts
@@ -138,15 +138,15 @@ describe("Orchestration Client", () => {
         it("calls expected webhook", async () => {
             const client = new DurableOrchestrationClient(defaultClientInputData);
 
-            const expectedStatus = new DurableOrchestrationStatus(
-                defaultOrchestrationName,
-                defaultInstanceId,
-                new Date(),
-                new Date(),
-                undefined,
-                undefined,
-                OrchestrationRuntimeStatus.Pending
-            );
+            const expectedStatus = new DurableOrchestrationStatus({
+                name: defaultOrchestrationName,
+                instanceId: defaultInstanceId,
+                createdTime: new Date(),
+                lastUpdatedTime: new Date(),
+                input: null,
+                output: null,
+                runtimeStatus: OrchestrationRuntimeStatus.Pending,
+            });
             const expectedWebhookUrl = new url.URL(
                 defaultClientInputData.managementUrls.statusQueryGetUri.replace(
                     TestConstants.idPlaceholder,
@@ -169,15 +169,15 @@ describe("Orchestration Client", () => {
         it("calls expected webhook when showHistory = true", async () => {
             const client = new DurableOrchestrationClient(defaultClientInputData);
 
-            const expectedStatus = new DurableOrchestrationStatus(
-                defaultOrchestrationName,
-                defaultInstanceId,
-                new Date(),
-                new Date(),
-                undefined,
-                undefined,
-                OrchestrationRuntimeStatus.Pending
-            );
+            const expectedStatus = new DurableOrchestrationStatus({
+                name: defaultOrchestrationName,
+                instanceId: defaultInstanceId,
+                createdTime: new Date(),
+                lastUpdatedTime: new Date(),
+                input: null,
+                output: null,
+                runtimeStatus: OrchestrationRuntimeStatus.Pending,
+            });
             const expectedWebhookUrl = new url.URL(
                 defaultClientInputData.managementUrls.statusQueryGetUri.replace(
                     TestConstants.idPlaceholder,
@@ -202,15 +202,15 @@ describe("Orchestration Client", () => {
         it("calls expected webhook when showHistoryOutput = true", async () => {
             const client = new DurableOrchestrationClient(defaultClientInputData);
 
-            const expectedStatus = new DurableOrchestrationStatus(
-                defaultOrchestrationName,
-                defaultInstanceId,
-                new Date(),
-                new Date(),
-                undefined,
-                undefined,
-                OrchestrationRuntimeStatus.Pending
-            );
+            const expectedStatus = new DurableOrchestrationStatus({
+                name: defaultOrchestrationName,
+                instanceId: defaultInstanceId,
+                createdTime: new Date(),
+                lastUpdatedTime: new Date(),
+                input: null,
+                output: null,
+                runtimeStatus: OrchestrationRuntimeStatus.Pending,
+            });
             const expectedWebhookUrl = new url.URL(
                 defaultClientInputData.managementUrls.statusQueryGetUri.replace(
                     TestConstants.idPlaceholder,
@@ -236,15 +236,15 @@ describe("Orchestration Client", () => {
         it("calls expected webhook when showInput = false", async () => {
             const client = new DurableOrchestrationClient(defaultClientInputData);
 
-            const expectedStatus = new DurableOrchestrationStatus(
-                defaultOrchestrationName,
-                defaultInstanceId,
-                new Date(),
-                new Date(),
-                undefined,
-                undefined,
-                OrchestrationRuntimeStatus.Pending
-            );
+            const expectedStatus = new DurableOrchestrationStatus({
+                name: defaultOrchestrationName,
+                instanceId: defaultInstanceId,
+                createdTime: new Date(),
+                lastUpdatedTime: new Date(),
+                input: null,
+                output: null,
+                runtimeStatus: OrchestrationRuntimeStatus.Pending,
+            });
             const expectedWebhookUrl = new url.URL(
                 defaultClientInputData.managementUrls.statusQueryGetUri.replace(
                     TestConstants.idPlaceholder,
@@ -268,7 +268,251 @@ describe("Orchestration Client", () => {
             expect(JSON.stringify(result)).to.be.equal(JSON.stringify(expectedStatus));
         });
 
-        // TODO: test status codes individually
+        describe("correctly handles 200 responses", async () => {
+            const client = new DurableOrchestrationClient(defaultClientInputData);
+
+            const expectedWebhookUrl = new url.URL(
+                defaultClientInputData.managementUrls.statusQueryGetUri.replace(
+                    TestConstants.idPlaceholder,
+                    defaultInstanceId
+                )
+            );
+
+            it("correctly handles Completed case", async () => {
+                const expectedStatus = new DurableOrchestrationStatus({
+                    name: defaultOrchestrationName,
+                    instanceId: defaultInstanceId,
+                    createdTime: new Date().toString(),
+                    lastUpdatedTime: new Date().toString(),
+                    input: null,
+                    output: "myOutput",
+                    runtimeStatus: OrchestrationRuntimeStatus.Completed,
+                });
+
+                const scope = nock(expectedWebhookUrl.origin)
+                    .get(expectedWebhookUrl.pathname)
+                    .query((actualQueryObject: object) =>
+                        urlQueryEqualsQueryObject(expectedWebhookUrl, actualQueryObject)
+                    )
+                    .reply(200, expectedStatus);
+
+                const result = await client.getStatus(defaultInstanceId);
+                expect(scope.isDone()).to.be.equal(true);
+                expect(JSON.stringify(result)).to.be.equal(JSON.stringify(expectedStatus));
+            });
+
+            it("correctly handles Failed case", async () => {
+                const expectedStatus = new DurableOrchestrationStatus({
+                    name: defaultOrchestrationName,
+                    instanceId: defaultInstanceId,
+                    createdTime: new Date().toString(),
+                    lastUpdatedTime: new Date().toString(),
+                    input: null,
+                    output: `Orchestrator function '${defaultOrchestrationName}' failed: Error`,
+                    runtimeStatus: OrchestrationRuntimeStatus.Failed,
+                });
+
+                const scope = nock(expectedWebhookUrl.origin)
+                    .get(expectedWebhookUrl.pathname)
+                    .query((actualQueryObject: object) =>
+                        urlQueryEqualsQueryObject(expectedWebhookUrl, actualQueryObject)
+                    )
+                    .reply(200, expectedStatus);
+
+                const result = await client.getStatus(defaultInstanceId);
+                expect(scope.isDone()).to.be.equal(true);
+                expect(JSON.stringify(result)).to.be.equal(JSON.stringify(expectedStatus));
+            });
+
+            it("correctly handles Terminated case", async () => {
+                const expectedStatus = new DurableOrchestrationStatus({
+                    name: defaultOrchestrationName,
+                    instanceId: defaultInstanceId,
+                    createdTime: new Date().toString(),
+                    lastUpdatedTime: new Date().toString(),
+                    input: null,
+                    output: `Termination reason`,
+                    runtimeStatus: OrchestrationRuntimeStatus.Terminated,
+                });
+
+                const scope = nock(expectedWebhookUrl.origin)
+                    .get(expectedWebhookUrl.pathname)
+                    .query((actualQueryObject: object) =>
+                        urlQueryEqualsQueryObject(expectedWebhookUrl, actualQueryObject)
+                    )
+                    .reply(200, expectedStatus);
+
+                const result = await client.getStatus(defaultInstanceId);
+                expect(scope.isDone()).to.be.equal(true);
+                expect(JSON.stringify(result)).to.be.equal(JSON.stringify(expectedStatus));
+            });
+        });
+
+        describe("correctly handles 202 responses", async () => {
+            const client = new DurableOrchestrationClient(defaultClientInputData);
+
+            const expectedWebhookUrl = new url.URL(
+                defaultClientInputData.managementUrls.statusQueryGetUri.replace(
+                    TestConstants.idPlaceholder,
+                    defaultInstanceId
+                )
+            );
+
+            it("correctly handles Pending case", async () => {
+                const expectedStatus = new DurableOrchestrationStatus({
+                    name: defaultOrchestrationName,
+                    instanceId: defaultInstanceId,
+                    createdTime: new Date().toString(),
+                    lastUpdatedTime: new Date().toString(),
+                    input: null,
+                    output: null,
+                    runtimeStatus: OrchestrationRuntimeStatus.Pending,
+                });
+
+                const scope = nock(expectedWebhookUrl.origin)
+                    .get(expectedWebhookUrl.pathname)
+                    .query((actualQueryObject: object) =>
+                        urlQueryEqualsQueryObject(expectedWebhookUrl, actualQueryObject)
+                    )
+                    .reply(202, expectedStatus);
+
+                const result = await client.getStatus(defaultInstanceId);
+                expect(scope.isDone()).to.be.equal(true);
+                expect(JSON.stringify(result)).to.be.equal(JSON.stringify(expectedStatus));
+            });
+
+            it("correctly handles Running case", async () => {
+                const expectedStatus = new DurableOrchestrationStatus({
+                    name: defaultOrchestrationName,
+                    instanceId: defaultInstanceId,
+                    createdTime: new Date().toString(),
+                    lastUpdatedTime: new Date().toString(),
+                    input: null,
+                    output: null,
+                    runtimeStatus: OrchestrationRuntimeStatus.Running,
+                });
+
+                const scope = nock(expectedWebhookUrl.origin)
+                    .get(expectedWebhookUrl.pathname)
+                    .query((actualQueryObject: object) =>
+                        urlQueryEqualsQueryObject(expectedWebhookUrl, actualQueryObject)
+                    )
+                    .reply(202, expectedStatus);
+
+                const result = await client.getStatus(defaultInstanceId);
+                expect(scope.isDone()).to.be.equal(true);
+                expect(JSON.stringify(result)).to.be.equal(JSON.stringify(expectedStatus));
+            });
+        });
+
+        it("throws on 500 responses", async () => {
+            const client = new DurableOrchestrationClient(defaultClientInputData);
+
+            const expectedWebhookUrl = new url.URL(
+                defaultClientInputData.managementUrls.statusQueryGetUri.replace(
+                    TestConstants.idPlaceholder,
+                    defaultInstanceId
+                )
+            );
+
+            const exception = {
+                Message: "Something went wrong while processing your request",
+                ExceptionType:
+                    "ExceptionType: 'DurableTask.AzureStorage.Storage.DurableTaskStorageException",
+                ExceptionMessage:
+                    "No connection could be made because the target machine actively refused it. (127.0.0.1:10002)",
+                StackTrace: "Sample stack trace",
+            };
+
+            nock(expectedWebhookUrl.origin)
+                .get(expectedWebhookUrl.pathname)
+                .query((actualQueryObject: object) =>
+                    urlQueryEqualsQueryObject(expectedWebhookUrl, actualQueryObject)
+                )
+                .reply(500, exception);
+
+            await expect(client.getStatus(defaultInstanceId)).to.be.rejectedWith(
+                `The operation failed with an unexpected status code: 500. Details: ${JSON.stringify(
+                    exception
+                )}`
+            );
+        });
+
+        it("Throws on empty response data", async () => {
+            const client = new DurableOrchestrationClient(defaultClientInputData);
+
+            const expectedWebhookUrl = new url.URL(
+                defaultClientInputData.managementUrls.statusQueryGetUri.replace(
+                    TestConstants.idPlaceholder,
+                    defaultInstanceId
+                )
+            );
+
+            nock(expectedWebhookUrl.origin)
+                .get(expectedWebhookUrl.pathname)
+                .query((actualQueryObject: object) =>
+                    urlQueryEqualsQueryObject(expectedWebhookUrl, actualQueryObject)
+                )
+                .reply(200, "");
+
+            await expect(client.getStatus(defaultInstanceId)).to.be.rejectedWith(
+                `DurableClient error: the Durable Functions extension replied with an empty HTTP 200 response.`
+            );
+        });
+
+        it("throws on malformed response data", async () => {
+            const client = new DurableOrchestrationClient(defaultClientInputData);
+
+            const expectedWebhookUrl = new url.URL(
+                defaultClientInputData.managementUrls.statusQueryGetUri.replace(
+                    TestConstants.idPlaceholder,
+                    defaultInstanceId
+                )
+            );
+
+            const statusInit = {
+                createdTime: new Date().toString(),
+                lastUpdatedTime: new Date().toString(),
+                input: null,
+                output: null,
+                runtimeStatus: OrchestrationRuntimeStatus.Running,
+            };
+
+            nock(expectedWebhookUrl.origin)
+                .get(expectedWebhookUrl.pathname)
+                .query((actualQueryObject: object) =>
+                    urlQueryEqualsQueryObject(expectedWebhookUrl, actualQueryObject)
+                )
+                .reply(202, statusInit);
+
+            await expect(client.getStatus(defaultInstanceId)).to.be.rejectedWith(
+                `DurableClient error: could not construct a DurableOrchestrationStatus object using the data received from the Durable Functions extension: ` +
+                    `Failed to construct a DurableOrchestrationStatus object because the initializer had invalid types or missing fields. ` +
+                    `Initializer received: ${JSON.stringify(statusInit)}`
+            );
+        });
+
+        it("throws on invalid instanceId", async () => {
+            const client = new DurableOrchestrationClient(defaultClientInputData);
+
+            const expectedWebhookUrl = new url.URL(
+                defaultClientInputData.managementUrls.statusQueryGetUri.replace(
+                    TestConstants.idPlaceholder,
+                    "nonExistentInstanceId"
+                )
+            );
+
+            nock(expectedWebhookUrl.origin)
+                .get(expectedWebhookUrl.pathname)
+                .query((actualQueryObject: object) =>
+                    urlQueryEqualsQueryObject(expectedWebhookUrl, actualQueryObject)
+                )
+                .reply(404, "");
+
+            await expect(client.getStatus("nonExistentInstanceId")).to.be.rejectedWith(
+                `DurableClient error: Durable Functions extension replied with HTTP 404 response. This usually means we could not find any data associated with the instanceId provided: nonExistentInstanceId.`
+            );
+        });
     });
 
     describe("getStatusAll()", () => {
@@ -291,15 +535,15 @@ describe("Orchestration Client", () => {
             );
 
             const expectedStatuses: DurableOrchestrationStatus[] = [
-                new DurableOrchestrationStatus(
-                    defaultOrchestrationName,
-                    defaultInstanceId,
-                    new Date(),
-                    new Date(),
-                    undefined,
-                    undefined,
-                    OrchestrationRuntimeStatus.Pending
-                ),
+                new DurableOrchestrationStatus({
+                    name: defaultOrchestrationName,
+                    instanceId: defaultInstanceId,
+                    createdTime: new Date(),
+                    lastUpdatedTime: new Date(),
+                    input: null,
+                    output: null,
+                    runtimeStatus: OrchestrationRuntimeStatus.Pending,
+                }),
             ];
             const scope = nock(expectedWebhookUrl.origin)
                 .get(expectedWebhookUrl.pathname)
@@ -342,17 +586,15 @@ describe("Orchestration Client", () => {
             );
 
             const expectedStatuses: DurableOrchestrationStatus[] = [
-                new DurableOrchestrationStatus(
-                    defaultOrchestrationName,
-                    defaultInstanceId,
-                    new Date(),
-                    new Date(),
-                    undefined,
-                    undefined,
-                    OrchestrationRuntimeStatus.Terminated,
-                    undefined,
-                    undefined
-                ),
+                new DurableOrchestrationStatus({
+                    name: defaultOrchestrationName,
+                    instanceId: defaultInstanceId,
+                    createdTime: new Date(),
+                    lastUpdatedTime: new Date(),
+                    input: null,
+                    output: null,
+                    runtimeStatus: OrchestrationRuntimeStatus.Terminated,
+                }),
             ];
             const scope = nock(expectedWebhookUrl.origin)
                 .get(expectedWebhookUrl.pathname)
@@ -1134,19 +1376,17 @@ describe("Orchestration Client", () => {
 
             const expectedOutput = 42;
 
-            const expectedStatus = new DurableOrchestrationStatus(
-                defaultOrchestrationName,
-                defaultInstanceId,
-                new Date(),
-                new Date(),
-                undefined,
-                expectedOutput,
-                OrchestrationRuntimeStatus.Completed,
-                undefined,
-                undefined
-            );
+            const expectedStatus = new DurableOrchestrationStatus({
+                name: defaultOrchestrationName,
+                instanceId: defaultInstanceId,
+                createdTime: new Date(),
+                lastUpdatedTime: new Date(),
+                input: null,
+                output: expectedOutput,
+                runtimeStatus: OrchestrationRuntimeStatus.Completed,
+            });
 
-            nock(Constants.DefaultLocalOrigin).get(/.*/).reply(202, expectedStatus);
+            nock(Constants.DefaultLocalOrigin).get(/.*/).reply(200, expectedStatus);
 
             const res = await client.waitForCompletionOrCreateCheckStatusResponse(
                 defaultRequest,
@@ -1166,15 +1406,15 @@ describe("Orchestration Client", () => {
         it("returns expected result for canceled instance", async () => {
             const client = new DurableOrchestrationClient(defaultClientInputData);
 
-            const expectedStatus = new DurableOrchestrationStatus(
-                defaultOrchestrationName,
-                defaultInstanceId,
-                new Date(),
-                new Date(),
-                undefined,
-                undefined,
-                OrchestrationRuntimeStatus.Canceled
-            );
+            const expectedStatus = new DurableOrchestrationStatus({
+                name: defaultOrchestrationName,
+                instanceId: defaultInstanceId,
+                createdTime: new Date(),
+                lastUpdatedTime: new Date(),
+                input: null,
+                output: null,
+                runtimeStatus: OrchestrationRuntimeStatus.Canceled,
+            });
 
             nock(Constants.DefaultLocalOrigin).get(/.*/).reply(202, expectedStatus);
 
@@ -1198,17 +1438,17 @@ describe("Orchestration Client", () => {
         it("returns expected result for terminated instance", async () => {
             const client = new DurableOrchestrationClient(defaultClientInputData);
 
-            const expectedStatus = new DurableOrchestrationStatus(
-                defaultOrchestrationName,
-                defaultInstanceId,
-                new Date(),
-                new Date(),
-                undefined,
-                undefined,
-                OrchestrationRuntimeStatus.Terminated
-            );
+            const expectedStatus = new DurableOrchestrationStatus({
+                name: defaultOrchestrationName,
+                instanceId: defaultInstanceId,
+                createdTime: new Date(),
+                lastUpdatedTime: new Date(),
+                input: null,
+                output: null,
+                runtimeStatus: OrchestrationRuntimeStatus.Terminated,
+            });
 
-            nock(Constants.DefaultLocalOrigin).get(/.*/).reply(202, expectedStatus);
+            nock(Constants.DefaultLocalOrigin).get(/.*/).reply(200, expectedStatus);
 
             const expectedStatusAsJson = JSON.stringify(expectedStatus);
 
@@ -1230,17 +1470,17 @@ describe("Orchestration Client", () => {
         it("returns expected result for failed instance", async () => {
             const client = new DurableOrchestrationClient(defaultClientInputData);
 
-            const expectedStatus = new DurableOrchestrationStatus(
-                defaultOrchestrationName,
-                defaultInstanceId,
-                new Date(),
-                new Date(),
-                undefined,
-                undefined,
-                OrchestrationRuntimeStatus.Failed
-            );
+            const expectedStatus = new DurableOrchestrationStatus({
+                name: defaultOrchestrationName,
+                instanceId: defaultInstanceId,
+                createdTime: new Date(),
+                lastUpdatedTime: new Date(),
+                input: null,
+                output: null,
+                runtimeStatus: OrchestrationRuntimeStatus.Failed,
+            });
 
-            nock(Constants.DefaultLocalOrigin).get(/.*/).reply(202, expectedStatus);
+            nock(Constants.DefaultLocalOrigin).get(/.*/).reply(200, expectedStatus);
 
             const expectedStatusAsJson = JSON.stringify(expectedStatus);
 
@@ -1264,24 +1504,24 @@ describe("Orchestration Client", () => {
 
             const expectedOutput = 42;
 
-            const runningStatus = new DurableOrchestrationStatus(
-                defaultOrchestrationName,
-                defaultInstanceId,
-                new Date(),
-                new Date(),
-                undefined,
-                undefined,
-                OrchestrationRuntimeStatus.Running
-            );
-            const completedStatus = new DurableOrchestrationStatus(
-                defaultOrchestrationName,
-                defaultInstanceId,
-                new Date(),
-                new Date(),
-                undefined,
-                expectedOutput,
-                OrchestrationRuntimeStatus.Completed
-            );
+            const runningStatus = new DurableOrchestrationStatus({
+                name: defaultOrchestrationName,
+                instanceId: defaultInstanceId,
+                createdTime: new Date(),
+                lastUpdatedTime: new Date(),
+                input: null,
+                output: null,
+                runtimeStatus: OrchestrationRuntimeStatus.Running,
+            });
+            const completedStatus = new DurableOrchestrationStatus({
+                name: defaultOrchestrationName,
+                instanceId: defaultInstanceId,
+                createdTime: new Date(),
+                lastUpdatedTime: new Date(),
+                input: null,
+                output: expectedOutput,
+                runtimeStatus: OrchestrationRuntimeStatus.Completed,
+            });
 
             const httpManagementPayload = TestUtils.createHttpManagementPayload(
                 defaultInstanceId,
@@ -1320,15 +1560,15 @@ describe("Orchestration Client", () => {
         it("returns check status response if timeout expires", async () => {
             const client = new DurableOrchestrationClient(defaultClientInputData);
 
-            const runningStatus = new DurableOrchestrationStatus(
-                defaultOrchestrationName,
-                defaultInstanceId,
-                new Date(),
-                new Date(),
-                undefined,
-                undefined,
-                OrchestrationRuntimeStatus.Running
-            );
+            const runningStatus = new DurableOrchestrationStatus({
+                name: defaultOrchestrationName,
+                instanceId: defaultInstanceId,
+                createdTime: new Date(),
+                lastUpdatedTime: new Date(),
+                input: null,
+                output: null,
+                runtimeStatus: OrchestrationRuntimeStatus.Running,
+            });
 
             const httpManagementPayload = TestUtils.createHttpManagementPayload(
                 defaultInstanceId,