public static async Task <TestDurableClient> StartOrchestratorAsync(
            this ITestHost host,
            string functionName,
            object input,
            ITestOutputHelper output,
            string instanceId = null,
            bool useTaskHubFromAppSettings = false)
        {
            var startFunction = useTaskHubFromAppSettings ?
                                typeof(ClientFunctions).GetMethod(nameof(ClientFunctions.StartFunctionWithTaskHub)) :
                                typeof(ClientFunctions).GetMethod(nameof(ClientFunctions.StartFunction));

            var clientRef = new TestDurableClient[1];
            var args      = new Dictionary <string, object>
            {
                { "functionName", functionName },
                { "instanceId", instanceId },
                { "input", input },
                { "clientRef", clientRef },
            };

            await host.CallAsync(startFunction, args);

            TestDurableClient client = clientRef[0];

            output.WriteLine($"Started {functionName}, Instance ID = {client.InstanceId}");
            return(client);
        }
        /// <summary>
        /// Helper function for the IDurableOrchestrationClientBinding test. Gets an IDurableOrchestrationClient.
        /// </summary>
        public static async Task <IDurableOrchestrationClient> GetOrchestrationClientBindingTest(
            this ITestHost host,
            ITestOutputHelper output)
        {
            var startFunction = typeof(ClientFunctions)
                                .GetMethod(nameof(ClientFunctions.GetOrchestrationClientBindingTest));

            var clientRef = new IDurableOrchestrationClient[1];
            var args      = new Dictionary <string, object>
            {
                { "clientRef", clientRef },
            };

            await host.CallAsync(startFunction, args);

            IDurableOrchestrationClient client = clientRef[0];

            return(client);
        }
        public static async Task <TestEntityClient> GetEntityClientAsync(
            this ITestHost host,
            EntityId entityId,
            ITestOutputHelper output)
        {
            var startFunction = typeof(ClientFunctions)
                                .GetMethod(nameof(ClientFunctions.GetEntityClient));

            var clientRef = new TestEntityClient[1];
            var args      = new Dictionary <string, object>
            {
                { "entityId", entityId },
                { "clientRef", clientRef },
            };

            await host.CallAsync(startFunction, args);

            TestEntityClient client = clientRef[0];

            return(client);
        }
Example #4
0
        public async Task BindToDurableClientAsString(bool localRcpEnabled)
        {
            Uri testNotificationUrl = new Uri("https://durable.edu/runtime/webhooks/durabletask?code=abcdefg");

            using (ITestHost host = TestHelpers.GetJobHost(
                       this.loggerProvider,
                       nameof(this.BindToDurableClientAsString) + localRcpEnabled.ToString(),
                       enableExtendedSessions: false,
                       localRpcEndpointEnabled: localRcpEnabled,
                       notificationUrl: testNotificationUrl))
            {
                await host.StartAsync();

                // Fetch the JSON that was passed to the DurableClient binding
                string[] jsonRef = new string[1];
                await host.CallAsync(
                    nameof(ClientFunctions.GetDurableClientConfigJson),
                    new Dictionary <string, object>
                {
                    { "jsonRef", jsonRef },
                });

                string jsonString = jsonRef[0];
                Assert.NotNull(jsonString);
                JObject outerJson = JObject.Parse(jsonString);

                // Expected format:
                // {
                //   "taskHubName": "BindToDurableClientAsStringV2",
                //   "creationUrls": {
                //     "createNewInstancePostUri": "https://durable.edu/runtime/webhooks/durabletask/orchestrators/{functionName}[/{instanceId}]",
                //     "createAndWaitOnNewInstancePostUri": "https://durable.edu/runtime/webhooks/durabletask/orchestrators/{functionName}[/{instanceId}]?timeout={timeoutInSeconds}&pollingInterval={intervalInSeconds}"
                //   },
                //   "managementUrls": {
                //     "id": "INSTANCEID",
                //     "statusQueryGetUri": "https://durable.edu/runtime/webhooks/durabletask/instances/INSTANCEID?taskHub=BindToDurableClientAsStringV2&connection=Storage",
                //     "sendEventPostUri": "https://durable.edu/runtime/webhooks/durabletask/instances/INSTANCEID/raiseEvent/{eventName}?taskHub=BindToDurableClientAsStringV2&connection=Storage",
                //     "terminatePostUri": "https://durable.edu/runtime/webhooks/durabletask/instances/INSTANCEID/terminate?reason={text}&taskHub=BindToDurableClientAsStringV2&connection=Storage",
                //     "rewindPostUri": "https://durable.edu/runtime/webhooks/durabletask/instances/INSTANCEID/rewind?reason={text}&taskHub=BindToDurableClientAsStringV2&connection=Storage",
                //     "purgeHistoryDeleteUri": "https://durable.edu/runtime/webhooks/durabletask/instances/INSTANCEID?taskHub=BindToDurableClientAsStringV2&connection=Storage"
                //   },
                //   "baseUrl": "https://durable.edu/runtime/webhooks/durabletask/",
                //   "requiredQueryStringParameters": "code=abcdefg",
                //   "rpcBaseUrl": "http://127.0.0.1:17071/durabletask/" (or null)
                // }

                Assert.True(outerJson.TryGetValue("taskHubName", out JToken taskHubName));
                Assert.StartsWith(nameof(this.BindToDurableClientAsString), (string)taskHubName);

                // Local function that validates presence and format of the URL payloads.
                void CommonUriValidation(JToken json, string fieldName, string[] requiredSegments)
                {
                    Assert.Equal(JTokenType.Object, json.Type);
                    JObject jObj = (JObject)json;

                    Assert.True(jObj.TryGetValue(fieldName, out JToken fieldValue));
                    Assert.True(Uri.TryCreate((string)fieldValue, UriKind.Absolute, out Uri uri));
                    Assert.StartsWith(testNotificationUrl.GetLeftPart(UriPartial.Path), uri.GetLeftPart(UriPartial.Path));

                    if (fieldName != "baseUrl")
                    {
                        Assert.Contains(testNotificationUrl.Query.TrimStart('?'), uri.Query);
                    }

                    foreach (string segment in requiredSegments)
                    {
                        Assert.Contains(segment, uri.OriginalString);
                    }
                }

                string[] creationUrlParams = new[] { "{functionName}", "{instanceId}" };

                // Legacy payload validation
                Assert.True(outerJson.TryGetValue("creationUrls", out JToken creationUrls));
                CommonUriValidation(creationUrls, "createNewInstancePostUri", creationUrlParams);
                CommonUriValidation(creationUrls, "createAndWaitOnNewInstancePostUri", creationUrlParams);

                Assert.True(outerJson.TryGetValue("managementUrls", out JToken managementUrls));
                Assert.Equal(JTokenType.Object, managementUrls.Type);
                Assert.True(((JObject)managementUrls).TryGetValue("id", out JToken idValue));
                Assert.Equal(JTokenType.String, idValue.Type);

                string   idPlaceholder       = (string)idValue;
                string[] managementUrlParams = new[] { idPlaceholder };
                CommonUriValidation(managementUrls, "statusQueryGetUri", managementUrlParams);
                CommonUriValidation(managementUrls, "sendEventPostUri", managementUrlParams);
                CommonUriValidation(managementUrls, "terminatePostUri", managementUrlParams);
                CommonUriValidation(managementUrls, "rewindPostUri", managementUrlParams);
                CommonUriValidation(managementUrls, "purgeHistoryDeleteUri", managementUrlParams);

                CommonUriValidation(outerJson, "baseUrl", new string[0]);

                Assert.True(outerJson.TryGetValue("requiredQueryStringParameters", out JToken requiredQueryStringParameters));
                Assert.Equal(testNotificationUrl.Query.Trim('?'), (string)requiredQueryStringParameters);

                Assert.True(outerJson.TryGetValue("rpcBaseUrl", out JToken rpcBaseUrl));

                if (localRcpEnabled)
                {
                    Assert.True(Uri.TryCreate((string)rpcBaseUrl, UriKind.Absolute, out Uri rpcBaseUri));
                    Assert.True(rpcBaseUri.IsLoopback);
                    Assert.Equal("http", rpcBaseUri.Scheme);
                    Assert.Equal("/durabletask/", rpcBaseUri.AbsolutePath);
                }
                else
                {
                    Assert.Equal(JTokenType.Null, rpcBaseUrl.Type);
                }
            }
        }