Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,7 @@ packages/
*/mono**
*/appSettings.json
api_referece/*
.sonarqube/
.sonarqube/
*.html
*.cobertura.xml
integration-test-report_*.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
</ItemGroup>

<ItemGroup>
<Folder Include="Helpers\" />
<Folder Include="IntegrationTest\" />
<Folder Include="Model\" />
<Folder Include="Mock\" />
Expand Down
8 changes: 6 additions & 2 deletions Contentstack.Management.Core.Tests/Contentstack.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
using System;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Reflection;
using Contentstack.Management.Core.Tests.Helpers;
using Contentstack.Management.Core.Tests.Model;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
Expand All @@ -19,7 +21,9 @@ private static readonly Lazy<ContentstackClient>
new Lazy<ContentstackClient>(() =>
{
ContentstackClientOptions options = Config.GetSection("Contentstack").Get<ContentstackClientOptions>();
return new ContentstackClient(new OptionsWrapper<ContentstackClientOptions>(options));
var handler = new LoggingHttpHandler();
var httpClient = new HttpClient(handler);
return new ContentstackClient(httpClient, options);
});


Expand Down
114 changes: 114 additions & 0 deletions Contentstack.Management.Core.Tests/Helpers/AssertLogger.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Contentstack.Management.Core.Tests.Helpers
{
public static class AssertLogger
{
public static void IsNotNull(object value, string name = "")
{
bool passed = value != null;
TestOutputLogger.LogAssertion($"IsNotNull({name})", "NotNull", value?.ToString() ?? "null", passed);
Assert.IsNotNull(value);
}

public static void IsNull(object value, string name = "")
{
bool passed = value == null;
TestOutputLogger.LogAssertion($"IsNull({name})", "null", value?.ToString() ?? "null", passed);
Assert.IsNull(value);
}

public static void AreEqual<T>(T expected, T actual, string name = "")
{
bool passed = Equals(expected, actual);
TestOutputLogger.LogAssertion($"AreEqual({name})", expected?.ToString() ?? "null", actual?.ToString() ?? "null", passed);
Assert.AreEqual(expected, actual);
}

public static void AreEqual<T>(T expected, T actual, string message, string name)
{
bool passed = Equals(expected, actual);
TestOutputLogger.LogAssertion($"AreEqual({name})", expected?.ToString() ?? "null", actual?.ToString() ?? "null", passed);
Assert.AreEqual(expected, actual, message);
}

public static void IsTrue(bool condition, string name = "")
{
TestOutputLogger.LogAssertion($"IsTrue({name})", "True", condition.ToString(), condition);
Assert.IsTrue(condition);
}

public static void IsTrue(bool condition, string message, string name)
{
TestOutputLogger.LogAssertion($"IsTrue({name})", "True", condition.ToString(), condition);
Assert.IsTrue(condition, message);
}

public static void IsFalse(bool condition, string name = "")
{
TestOutputLogger.LogAssertion($"IsFalse({name})", "False", condition.ToString(), !condition);
Assert.IsFalse(condition);
}

public static void IsFalse(bool condition, string message, string name)
{
TestOutputLogger.LogAssertion($"IsFalse({name})", "False", condition.ToString(), !condition);
Assert.IsFalse(condition, message);
}

public static void IsInstanceOfType(object value, Type expectedType, string name = "")
{
bool passed = value != null && expectedType.IsInstanceOfType(value);
TestOutputLogger.LogAssertion(
$"IsInstanceOfType({name})",
expectedType?.Name ?? "null",
value?.GetType()?.Name ?? "null",
passed);
Assert.IsInstanceOfType(value, expectedType);
}

public static T ThrowsException<T>(Action action, string name = "") where T : Exception
{
try
{
action();
TestOutputLogger.LogAssertion($"ThrowsException<{typeof(T).Name}>({name})", typeof(T).Name, "NoException", false);
throw new AssertFailedException($"Expected exception {typeof(T).Name} was not thrown.");
}
catch (T ex)
{
TestOutputLogger.LogAssertion($"ThrowsException<{typeof(T).Name}>({name})", typeof(T).Name, typeof(T).Name, true);
return ex;
}
catch (AssertFailedException)
{
throw;
}
catch (Exception ex)
{
TestOutputLogger.LogAssertion($"ThrowsException<{typeof(T).Name}>({name})", typeof(T).Name, ex.GetType().Name, false);
throw new AssertFailedException(
$"Expected exception {typeof(T).Name} but got {ex.GetType().Name}: {ex.Message}", ex);
}
}

public static void Fail(string message)
{
TestOutputLogger.LogAssertion("Fail", "N/A", message ?? "", false);
Assert.Fail(message);
}

public static void Fail(string message, params object[] parameters)
{
TestOutputLogger.LogAssertion("Fail", "N/A", message ?? "", false);
Assert.Fail(message, parameters);
}

public static void Inconclusive(string message)
{
TestOutputLogger.LogAssertion("Inconclusive", "N/A", message ?? "", false);
Assert.Inconclusive(message);
}
}
}
110 changes: 110 additions & 0 deletions Contentstack.Management.Core.Tests/Helpers/LoggingHttpHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Contentstack.Management.Core.Tests.Helpers
{
public class LoggingHttpHandler : DelegatingHandler
{
public LoggingHttpHandler() : base(new HttpClientHandler()) { }
public LoggingHttpHandler(HttpMessageHandler innerHandler) : base(innerHandler) { }

protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
try
{
await CaptureRequest(request);
}
catch
{
// Never let logging break the request
}

var response = await base.SendAsync(request, cancellationToken);

try
{
await CaptureResponse(response);
}
catch
{
// Never let logging break the response
}

return response;
}

private async Task CaptureRequest(HttpRequestMessage request)
{
var headers = new Dictionary<string, string>();
foreach (var h in request.Headers)
headers[h.Key] = string.Join(", ", h.Value);

string body = null;
if (request.Content != null)
{
foreach (var h in request.Content.Headers)
headers[h.Key] = string.Join(", ", h.Value);

await request.Content.LoadIntoBufferAsync();
body = await request.Content.ReadAsStringAsync();
}

var curl = BuildCurl(request.Method.ToString(), request.RequestUri?.ToString(), headers, body);

TestOutputLogger.LogHttpRequest(
method: request.Method.ToString(),
url: request.RequestUri?.ToString() ?? "",
headers: headers,
body: body ?? "",
curlCommand: curl,
sdkMethod: ""
);
}

private async Task CaptureResponse(HttpResponseMessage response)
{
var headers = new Dictionary<string, string>();
foreach (var h in response.Headers)
headers[h.Key] = string.Join(", ", h.Value);

string body = null;
if (response.Content != null)
{
foreach (var h in response.Content.Headers)
headers[h.Key] = string.Join(", ", h.Value);

await response.Content.LoadIntoBufferAsync();
body = await response.Content.ReadAsStringAsync();
}

TestOutputLogger.LogHttpResponse(
statusCode: (int)response.StatusCode,
statusText: response.ReasonPhrase ?? response.StatusCode.ToString(),
headers: headers,
body: body ?? ""
);
}

private static string BuildCurl(string method, string url,
IDictionary<string, string> headers, string body)
{
var sb = new StringBuilder();
sb.Append($"curl -X {method} \\\n");
sb.Append($" '{url}' \\\n");
foreach (var kv in headers)
sb.Append($" -H '{kv.Key}: {kv.Value}' \\\n");
if (!string.IsNullOrEmpty(body))
{
var escaped = body.Replace("'", "'\\''");
sb.Append($" -d '{escaped}'");
}
return sb.ToString().TrimEnd('\\', '\n', ' ');
}
}
}
78 changes: 78 additions & 0 deletions Contentstack.Management.Core.Tests/Helpers/TestOutputLogger.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;

namespace Contentstack.Management.Core.Tests.Helpers
{
public static class TestOutputLogger
{
private const string START_MARKER = "###TEST_OUTPUT_START###";
private const string END_MARKER = "###TEST_OUTPUT_END###";

public static void LogAssertion(string assertionName, object expected, object actual, bool passed)
{
Emit(new Dictionary<string, object>
{
{ "type", "ASSERTION" },
{ "assertionName", assertionName },
{ "expected", expected?.ToString() ?? "null" },
{ "actual", actual?.ToString() ?? "null" },
{ "passed", passed }
});
}

public static void LogHttpRequest(string method, string url,
IDictionary<string, string> headers, string body,
string curlCommand, string sdkMethod)
{
Emit(new Dictionary<string, object>
{
{ "type", "HTTP_REQUEST" },
{ "method", method ?? "" },
{ "url", url ?? "" },
{ "headers", headers ?? new Dictionary<string, string>() },
{ "body", body ?? "" },
{ "curlCommand", curlCommand ?? "" },
{ "sdkMethod", sdkMethod ?? "" }
});
}

public static void LogHttpResponse(int statusCode, string statusText,
IDictionary<string, string> headers, string body)
{
Emit(new Dictionary<string, object>
{
{ "type", "HTTP_RESPONSE" },
{ "statusCode", statusCode },
{ "statusText", statusText ?? "" },
{ "headers", headers ?? new Dictionary<string, string>() },
{ "body", body ?? "" }
});
}

public static void LogContext(string key, string value)
{
Emit(new Dictionary<string, object>
{
{ "type", "CONTEXT" },
{ "key", key ?? "" },
{ "value", value ?? "" }
});
}

private static void Emit(object data)
{
try
{
var json = JsonConvert.SerializeObject(data, Formatting.None);
Console.Write(START_MARKER);
Console.Write(json);
Console.WriteLine(END_MARKER);
}
catch
{
// Never let logging break a test
}
}
}
}
Loading
Loading