Exemplo n.º 1
0
 protected void ResultCheck(WebApiAgentResult result)
 {
     if (_expectedStatusCode != null)
     {
         Assert.AreEqual(_expectedStatusCode, result.StatusCode);
     }
 }
Exemplo n.º 2
0
        /// <summary>
        /// Send a <see cref="HttpMethod"/> <b>PATCH</b> <paramref name="json"/> request as an asynchronous operation.
        /// </summary>
        /// <param name="urlSuffix">The url suffix for the operation.</param>
        /// <param name="patchOption">The <see cref="WebApiPatchOption"/>.</param>
        /// <param name="json">The json value.</param>
        /// <param name="requestOptions">The optional <see cref="WebApiRequestOptions"/>.</param>
        /// <param name="args">The operation arguments to be substituted within the <paramref name="urlSuffix"/>.</param>
        /// <param name="memberName">The method or property name of the caller to the method.</param>
        /// <param name="filePath">The full path of the source file that contains the caller.</param>
        /// <param name="lineNumber">The line number in the source file at which the method is called.</param>
        /// <returns>The <see cref="WebApiAgentResult{TResult}"/>.</returns>
        public async Task <WebApiAgentResult> PatchAsync(string urlSuffix, WebApiPatchOption patchOption, JToken json, WebApiRequestOptions?requestOptions = null, WebApiArg[]?args = null, [CallerMemberName] string?memberName = null, [CallerFilePath] string?filePath = null, [CallerLineNumber] int lineNumber = 0)
        {
            if (json == null)
            {
                throw new ArgumentNullException(nameof(json));
            }

            if (patchOption == WebApiPatchOption.NotSpecified)
            {
                throw new ArgumentException("A valid patch option must be specified.", nameof(patchOption));
            }

            var uri = CreateFullUri(urlSuffix, args, requestOptions);

            if (args != null && args.Any(x => x.ArgType == WebApiArgType.FromBody))
            {
                throw new ArgumentException("No arguments can be marked as IsFromBody for a PATCH.", nameof(args));
            }

            return(await WebApiServiceAgentInvoker.Default.InvokeAsync(this, async() =>
            {
                var content = new StringContent(json.ToString());
                content.Headers.ContentType = MediaTypeHeaderValue.Parse(patchOption == WebApiPatchOption.JsonPatch ? "application/json-patch+json" : "application/merge-patch+json");
                var result = new WebApiAgentResult(await Client.SendAsync(CreateRequestMessage(new HttpMethod("PATCH"), uri, content, requestOptions)).ConfigureAwait(false));
                result.Content = await result.Response.Content.ReadAsStringAsync().ConfigureAwait(false);
                return VerifyResult(result);
            }, json, memberName, filePath, lineNumber).ConfigureAwait(false));
        }
Exemplo n.º 3
0
        /// <summary>
        /// Send a <see cref="HttpMethod.Delete"/> request as an asynchronous operation.
        /// </summary>
        /// <param name="urlSuffix">The url suffix for the operation.</param>
        /// <param name="requestOptions">The optional <see cref="WebApiRequestOptions"/>.</param>
        /// <param name="args">The operation arguments to be substituted within the <paramref name="urlSuffix"/>.</param>
        /// <param name="memberName">The method or property name of the caller to the method.</param>
        /// <param name="filePath">The full path of the source file that contains the caller.</param>
        /// <param name="lineNumber">The line number in the source file at which the method is called.</param>
        /// <returns>The <see cref="WebApiAgentResult{T}"/>.</returns>
        public async Task <WebApiAgentResult> DeleteAsync(string urlSuffix, WebApiRequestOptions?requestOptions = null, WebApiArg[]?args = null, [CallerMemberName] string?memberName = null, [CallerFilePath] string?filePath = null, [CallerLineNumber] int lineNumber = 0)
        {
            var uri = CreateFullUri(urlSuffix, args, requestOptions);

            return(await WebApiServiceAgentInvoker.Default.InvokeAsync(this, async() =>
            {
                var result = new WebApiAgentResult(await Client.SendAsync(CreateRequestMessage(HttpMethod.Delete, uri, requestOptions: requestOptions)).ConfigureAwait(false));
                result.Content = await result.Response.Content.ReadAsStringAsync().ConfigureAwait(false);
                return VerifyResult(result);
            }, null !, memberName, filePath, lineNumber).ConfigureAwait(false));
        }
Exemplo n.º 4
0
        /// <summary>
        /// Send a <see cref="HttpMethod.Post"/> request as an asynchronous operation with an expected response.
        /// </summary>
        /// <typeparam name="TResult">The result <see cref="Type"/>.</typeparam>
        /// <param name="urlSuffix">The url suffix for the operation.</param>
        /// <param name="requestOptions">The optional <see cref="WebApiRequestOptions"/>.</param>
        /// <param name="args">The operation arguments to be substituted within the <paramref name="urlSuffix"/>.</param>
        /// <param name="memberName">The method or property name of the caller to the method.</param>
        /// <param name="filePath">The full path of the source file that contains the caller.</param>
        /// <param name="lineNumber">The line number in the source file at which the method is called.</param>
        /// <returns>The <see cref="WebApiAgentResult{TResult}"/>.</returns>
        public async Task <WebApiAgentResult <TResult> > PostAsync <TResult>(string urlSuffix, WebApiRequestOptions?requestOptions = null, WebApiArg[]?args = null, [CallerMemberName] string?memberName = null, [CallerFilePath] string?filePath = null, [CallerLineNumber] int lineNumber = 0)
        {
            var uri = CreateFullUri(urlSuffix, args, requestOptions);

            return(await WebApiServiceAgentInvoker.Default.InvokeAsync(this, async() =>
            {
                var value = args?.Where(x => x.ArgType == WebApiArgType.FromBody).SingleOrDefault()?.GetValue();
                var result = new WebApiAgentResult(await Client.SendAsync(CreateRequestMessage(HttpMethod.Post, uri, CreateJsonContentFromValue(value), requestOptions)).ConfigureAwait(false));
                result.Content = await result.Response.Content.ReadAsStringAsync().ConfigureAwait(false);
                return new WebApiAgentResult <TResult>(VerifyResult(result));
            }, null !, memberName, filePath, lineNumber).ConfigureAwait(false));
        }
Exemplo n.º 5
0
        /// <summary>
        /// Runs the <paramref name="func"/> where the agent is self-instantied and executed asynchonously checking against the expected outcomes.
        /// </summary>
        /// <param name="func">The function to execute.</param>
        /// <returns>The corresponding <see cref="Task{TResult}"/>.</returns>
        public async Task <WebApiAgentResult> RunOverrideAsync(Func <Task <WebApiAgentResult> > func)
        {
            if (func == null)
            {
                throw new ArgumentNullException(nameof(func));
            }

            var sw = Stopwatch.StartNew();
            WebApiAgentResult result = await func().ConfigureAwait(false);

            sw.Stop();
            ResultCheck(result, sw);
            PublishedEventsCheck();
            return(result);
        }
Exemplo n.º 6
0
        /// <summary>
        /// Send a <see cref="HttpMethod.Post"/> <paramref name="value"/> request as an asynchronous operation with an expected response.
        /// </summary>
        /// <typeparam name="TResult">The result <see cref="Type"/>.</typeparam>
        /// <param name="urlSuffix">The url suffix for the operation.</param>
        /// <param name="value">The content value.</param>
        /// <param name="requestOptions">The optional <see cref="WebApiRequestOptions"/>.</param>
        /// <param name="args">The operation arguments to be substituted within the <paramref name="urlSuffix"/>.</param>
        /// <param name="memberName">The method or property name of the caller to the method.</param>
        /// <param name="filePath">The full path of the source file that contains the caller.</param>
        /// <param name="lineNumber">The line number in the source file at which the method is called.</param>
        /// <returns>The <see cref="WebApiAgentResult{TResult}"/>.</returns>
        public async Task <WebApiAgentResult <TResult> > PostAsync <TResult>(string urlSuffix, object value, WebApiRequestOptions?requestOptions = null, WebApiArg[]?args = null, [CallerMemberName] string?memberName = null, [CallerFilePath] string?filePath = null, [CallerLineNumber] int lineNumber = 0)
        {
            if (value == null)
            {
                throw new ArgumentNullException(nameof(value));
            }

            var uri = CreateFullUri(urlSuffix, args, requestOptions);

            if (args != null && args.Any(x => x.ArgType == WebApiArgType.FromBody))
            {
                throw new ArgumentException("No arguments can be marked as IsFromBody where a content value is used.", nameof(args));
            }

            return(await WebApiServiceAgentInvoker.Default.InvokeAsync(this, async() =>
            {
                var result = new WebApiAgentResult(await Client.SendAsync(CreateRequestMessage(HttpMethod.Post, uri, CreateJsonContentFromValue(value), requestOptions)).ConfigureAwait(false));
                result.Content = await result.Response.Content.ReadAsStringAsync().ConfigureAwait(false);
                return new WebApiAgentResult <TResult>(VerifyResult(result));
            }, value, memberName, filePath, lineNumber).ConfigureAwait(false));
        }
Exemplo n.º 7
0
 private void LogResult(WebApiAgentResult result)
 {
     _logger.LogInformation($"REQUEST{Environment.NewLine}{result.Request}");
     _logger.LogInformation($"RESPONSE{Environment.NewLine}{result.Response}");
 }
Exemplo n.º 8
0
        /// <summary>
        /// Check the result to make sure it is valid.
        /// </summary>
        /// <param name="result">The <see cref="WebApiAgentResult"/>.</param>
        /// <param name="sw">The <see cref="Stopwatch"/> used to measure <see cref="WebApiAgentBase"/> invocation.</param>
        protected void ResultCheck(WebApiAgentResult result, Stopwatch sw)
        {
            if (result == null)
            {
                throw new ArgumentNullException(nameof(result));
            }

            // Log to output.
            TestContext.Out.WriteLine("");
            TestContext.Out.WriteLine("AGENT TESTER...");
            TestContext.Out.WriteLine("");
            TestContext.Out.WriteLine($"REQUEST >");
            TestContext.Out.WriteLine($"Request: {result.Request.Method} {result.Request.RequestUri}");

            if (!string.IsNullOrEmpty(Username))
            {
                TestContext.Out.WriteLine($"Username: {Username}");
            }

            TestContext.Out.WriteLine($"Headers: {(result.Request.Headers == null || !result.Request.Headers.Any() ? "none" : "")}");
            if (result.Request.Headers != null && result.Request.Headers.Any())
            {
                foreach (var hdr in result.Request.Headers)
                {
                    var sb = new StringBuilder();
                    foreach (var v in hdr.Value)
                    {
                        if (sb.Length > 0)
                        {
                            sb.Append(", ");
                        }

                        sb.Append(v);
                    }

                    TestContext.Out.WriteLine($"  {hdr.Key}: {sb}");
                }
            }

            JToken?json = null;

            if (result.Request.Content != null)
            {
                // HACK: The Request Content is a forward only stream that is already read; we need to reset this private variable back to the start.
                if (result.Request.Content is StreamContent)
                {
                    var fi = typeof(StreamContent).GetField("_content", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
                    var ms = (MemoryStream)fi !.GetValue(result.Request.Content) !;
                    ms.Position = 0;
                }

                // Parse out the content.
                try
                {
                    json = JToken.Parse(result.Request.Content.ReadAsStringAsync().Result);
                }
#pragma warning disable CA1031 // Do not catch general exception types; by-design.
                catch (Exception) { }
#pragma warning restore CA1031

                TestContext.Out.WriteLine($"Content: [{result.Request.Content?.Headers?.ContentType?.MediaType ?? "None"}]");
                TestContext.Out.WriteLine(json == null ? result.Request.Content?.ToString() : json.ToString());
            }

            TestContext.Out.WriteLine("");
            TestContext.Out.WriteLine($"RESPONSE >");
            TestContext.Out.WriteLine($"HttpStatusCode: {result.StatusCode} ({(int)result.StatusCode})");
            TestContext.Out.WriteLine($"Elapsed (ms): {(sw == null ? "none" : sw.ElapsedMilliseconds.ToString(System.Globalization.CultureInfo.InvariantCulture))}");

            var hdrs = result.Response?.Headers?.ToString().Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries);
            TestContext.Out.WriteLine($"Headers: {(hdrs == null || !hdrs.Any() ? "none" : "")}");
            if (hdrs != null && hdrs.Any())
            {
                foreach (var hdr in hdrs)
                {
                    TestContext.Out.WriteLine($"  {hdr}");
                }
            }

            TestContext.Out.WriteLine($"Messages: {(result.Messages == null || result.Messages.Count == 0 ? "none" : "")}");

            if (result.Messages != null && result.Messages.Count > 0)
            {
                foreach (var m in result.Messages)
                {
                    TestContext.Out.WriteLine($" {m.Type}: {m.Text} {(m.Property == null ? "" : "(" + m.Property + ")")}");
                }

                TestContext.Out.WriteLine("");
            }

            json = null;
            if (!string.IsNullOrEmpty(result.Content) && result.Response?.Content?.Headers?.ContentType?.MediaType == "application/json")
            {
                try
                {
                    json = JToken.Parse(result.Content);
                }
#pragma warning disable CA1031 // Do not catch general exception types; by-design.
                catch (Exception) { /* This is being swallowed by design. */ }
#pragma warning restore CA1031
            }

            TestContext.Out.Write($"Content: [{result.Response?.Content?.Headers?.ContentType?.MediaType ?? "none"}]");
            if (json != null)
            {
                TestContext.Out.WriteLine("");
                TestContext.Out.WriteLine(json.ToString());
            }
            else
            {
                TestContext.Out.WriteLine($"{(string.IsNullOrEmpty(result.Content) ? "none" : result.Content)}");
            }

            TestContext.Out.WriteLine("");
            TestContext.Out.WriteLine($"EVENTS PUBLISHED >");
            var events = ExpectEvent.GetEvents(CorrelationId);
            if (events.Count == 0)
            {
                TestContext.Out.WriteLine("  None.");
            }
            else
            {
                foreach (var e in events)
                {
                    TestContext.Out.WriteLine($"  Subject: {e.Subject}, Action: {e.Action}");
                }
            }

            TestContext.Out.WriteLine("");
            TestContext.Out.WriteLine($"LOGGING >");
            var messages = CorrelationIdLogger.GetMessages(CorrelationId);
            if (messages.Count == 0)
            {
                TestContext.Out.WriteLine("  None.");
            }
            else
            {
                foreach (var l in messages)
                {
                    TestContext.Out.WriteLine($"{l}");
                }
            }

            TestContext.Out.WriteLine("");
            TestContext.Out.WriteLine(new string('=', 80));
            TestContext.Out.WriteLine("");

            // Perform checks.
            if (_expectedStatusCode.HasValue && _expectedStatusCode != result.StatusCode)
            {
                Assert.Fail($"Expected HttpStatusCode was '{_expectedStatusCode} ({(int)_expectedStatusCode})'; actual was {result.StatusCode} ({(int)result.StatusCode}).");
            }

            if (_expectedErrorType.HasValue && _expectedErrorType != result.ErrorType)
            {
                Assert.Fail($"Expected ErrorType was '{_expectedErrorType}'; actual was '{result.ErrorType}'.");
            }

            if (_expectedErrorMessage != null && _expectedErrorMessage != result.ErrorMessage)
            {
                Assert.Fail($"Expected ErrorMessage was '{_expectedErrorMessage}'; actual was '{result.ErrorMessage}'.");
            }

            if (_expectedMessages != null)
            {
                ExpectValidationException.CompareExpectedVsActual(_expectedMessages, result.Messages);
            }
        }
Exemplo n.º 9
0
        /// <summary>
        /// Check the result to make sure it is valid.
        /// </summary>
        /// <param name="result">The <see cref="WebApiAgentResult"/>.</param>
        /// <param name="sw">The <see cref="Stopwatch"/> used to measure <see cref="WebApiServiceAgentBase"/> invocation.</param>
        protected void ResultCheck(WebApiAgentResult result, Stopwatch sw)
        {
            Check.NotNull(result, nameof(result));

            // Log to output.
            Logger.Default.Info("");
            Logger.Default.Info("AGENT TESTER...");
            Logger.Default.Info("");
            Logger.Default.Info($"REQUEST >");
            Logger.Default.Info($"Request: {result.Request.Method} {result.Request.RequestUri}");

            if (!string.IsNullOrEmpty(Username))
            {
                Logger.Default.Info($"Username: {Username}");
            }

            Logger.Default.Info($"Headers: {(result.Request.Headers == null || !result.Request.Headers.Any() ? "none" : "")}");
            if (result.Request.Headers != null && result.Request.Headers.Any())
            {
                foreach (var hdr in result.Request.Headers)
                {
                    var sb = new StringBuilder();
                    foreach (var v in hdr.Value)
                    {
                        if (sb.Length > 0)
                        {
                            sb.Append(", ");
                        }

                        sb.Append(v);
                    }

                    Logger.Default.Info($"  {hdr.Key}: {sb}");
                }
            }

            JToken json = null;

            if (result.Request.Content != null)
            {
                try
                {
                    json = JToken.Parse(result.Request.Content.ReadAsStringAsync().Result);
                }
                catch (Exception) { }

                Logger.Default.Info($"Content [{result.Request.Content?.Headers?.ContentType?.MediaType}]:");
                Logger.Default.Info(json == null ? result.Request.Content.ToString() : json.ToString());
            }

            Logger.Default.Info("");
            Logger.Default.Info($"RESPONSE >");
            Logger.Default.Info($"HttpStatusCode: {result.StatusCode} ({(int)result.StatusCode})");
            Logger.Default.Info($"Elapsed (ms): {(sw == null ? "none" : sw.ElapsedMilliseconds.ToString())}");

            var hdrs = result.Response?.Headers?.ToString().Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries);

            Logger.Default.Info($"Headers: {(hdrs == null || !hdrs.Any() ? "none" : "")}");
            if (hdrs != null && hdrs.Any())
            {
                foreach (var hdr in hdrs)
                {
                    Logger.Default.Info($"  {hdr}");
                }
            }

            Logger.Default.Info($"Messages: {(result.Messages == null || result.Messages.Count == 0 ? "none" : "")}");

            if (result.Messages != null && result.Messages.Count > 0)
            {
                foreach (var m in result.Messages)
                {
                    Logger.Default.Info($" {m.Type}: {m.Text} {(m.Property == null ? "" : "(" + m.Property + ")")}");
                }

                Logger.Default.Info(null);
            }

            json = null;
            if (!string.IsNullOrEmpty(result.Content) && result.Response?.Content?.Headers?.ContentType?.MediaType == "application/json")
            {
                try
                {
                    json = JToken.Parse(result.Content);
                }
                catch (Exception) { /* This is being swallowed by design. */ }
            }

            TestContext.Out.Write($"Content: ");
            if (json != null)
            {
                Logger.Default.Info(null);
                Logger.Default.Info(json.ToString());
            }
            else
            {
                Logger.Default.Info($"{(string.IsNullOrEmpty(result.Content) ? "none" : result.Content)}");
            }

            Logger.Default.Info(null);
            Logger.Default.Info(new string('=', 80));
            Logger.Default.Info(null);

            // Perform checks.
            if (_expectedStatusCode.HasValue && _expectedStatusCode != result.StatusCode)
            {
                Assert.Fail($"Expected HttpStatusCode was '{_expectedStatusCode} ({(int)_expectedStatusCode})'; actual was {result.StatusCode} ({(int)result.StatusCode}).");
            }

            if (_expectedErrorType.HasValue && _expectedErrorType != result.ErrorType)
            {
                Assert.Fail($"Expected ErrorType was '{_expectedErrorType}'; actual was '{result.ErrorType}'.");
            }

            if (_expectedErrorMessage != null && _expectedErrorMessage != result.ErrorMessage)
            {
                Assert.Fail($"Expected ErrorMessage was '{_expectedErrorMessage}'; actual was '{result.ErrorMessage}'.");
            }

            if (_expectedMessages != null)
            {
                ExpectValidationException.CompareExpectedVsActual(_expectedMessages, result.Messages);
            }
        }