Skip to content
Open
Show file tree
Hide file tree
Changes from all 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