This commit is contained in:
Janus C. H. Knudsen 2025-03-07 00:17:08 +01:00
parent 0010a32248
commit ddb6abc14e
14 changed files with 754 additions and 718 deletions

View file

@ -1,21 +1,23 @@
using Npgsql; using Npgsql;
class TestPostgresLISTENNOTIFY namespace PlanTempus.X.TDD.CodeSnippets;
internal class TestPostgresLISTENNOTIFY
{ {
static async Task Main(string[] args) private static async Task Main(string[] args)
{ {
var connectionString = "Host=192.168.1.57;Database=ptdb01;Username=postgres;Password=3911"; var connectionString = "Host=192.168.1.57;Database=ptdb01;Username=postgres;Password=3911";
try try
{ {
await using NpgsqlConnection conn = new NpgsqlConnection(connectionString); await using var conn = new NpgsqlConnection(connectionString);
await conn.OpenAsync(); await conn.OpenAsync();
Console.WriteLine("Forbundet til databasen. Lytter efter notifikationer..."); Console.WriteLine("Forbundet til databasen. Lytter efter notifikationer...");
conn.Notification += (o, e) => conn.Notification += (o, e) =>
{ {
Console.WriteLine($"Notifikation modtaget:"); Console.WriteLine("Notifikation modtaget:");
Console.WriteLine($" PID: {e.PID}"); Console.WriteLine($" PID: {e.PID}");
Console.WriteLine($" Kanal: {e.Channel}"); Console.WriteLine($" Kanal: {e.Channel}");
Console.WriteLine($" Payload: {e.Payload}"); Console.WriteLine($" Payload: {e.Payload}");
@ -29,10 +31,7 @@ class TestPostgresLISTENNOTIFY
Console.WriteLine("Tryk på en tast for at stoppe..."); Console.WriteLine("Tryk på en tast for at stoppe...");
while (!Console.KeyAvailable) while (!Console.KeyAvailable) await conn.WaitAsync();
{
await conn.WaitAsync();
}
} }
catch (Exception ex) catch (Exception ex)
{ {

View file

@ -1,18 +1,16 @@
using PlanTempus.Database.ConfigurationManagementSystem; using System.Data;
using Insight.Database;
using System.Data;
using Newtonsoft.Json;
using Autofac; using Autofac;
using Shouldly; using Insight.Database;
using Newtonsoft.Json;
using PlanTempus.Core.Sql.ConnectionFactory; using PlanTempus.Core.Sql.ConnectionFactory;
using Shouldly;
namespace PlanTempus.Tests.ConfigurationSystem; namespace PlanTempus.X.TDD.ConfigurationSystem;
[TestClass] [TestClass]
public class SetupConfigurationTests : TestFixture public class SetupConfigurationTests : TestFixture
{ {
private IDbConnection _connection; private IDbConnection _connection;
private SetupConfiguration _setupConfiguration;
[TestInitialize] [TestInitialize]
public void Setup() public void Setup()
@ -52,15 +50,15 @@ public class SetupConfigurationTests : TestFixture
SELECT key, value, label, action_type SELECT key, value, label, action_type
FROM app_configuration_history FROM app_configuration_history
WHERE id = @id AND action_type = 'I'", WHERE id = @id AND action_type = 'I'",
new { id = (int)result.id }) new { id = (int)result.id })
.Single(); .Single();
// Assert // Assert
var expected = JsonConvert.SerializeObject(new var expected = JsonConvert.SerializeObject(new
{ {
key = configData.key, configData.key,
value = configData.value, configData.value,
label = configData.label, configData.label,
action_type = "I" action_type = "I"
}); });
var actual = JsonConvert.SerializeObject(history) as string; var actual = JsonConvert.SerializeObject(history) as string;
@ -83,7 +81,7 @@ public class SetupConfigurationTests : TestFixture
RETURNING modified_at", configData) RETURNING modified_at", configData)
.Single(); .Single();
System.Threading.Thread.Sleep(1000); Thread.Sleep(1000);
// Act // Act
var updated = _connection.QuerySql<dynamic>(@" var updated = _connection.QuerySql<dynamic>(@"
@ -91,7 +89,7 @@ public class SetupConfigurationTests : TestFixture
SET value = @value SET value = @value
WHERE key = @key WHERE key = @key
RETURNING modified_at", RETURNING modified_at",
new { key = configData.key, value = "updated value" }) new { configData.key, value = "updated value" })
.Single(); .Single();
// Assert // Assert
@ -124,13 +122,13 @@ public class SetupConfigurationTests : TestFixture
SELECT key, value, action_type SELECT key, value, action_type
FROM app_configuration_history FROM app_configuration_history
WHERE id = @id AND action_type = 'D'", WHERE id = @id AND action_type = 'D'",
new { id = (int)original.id }) new { id = (int)original.id })
.Single(); .Single();
var expected = JsonConvert.SerializeObject(new var expected = JsonConvert.SerializeObject(new
{ {
key = configData.key, configData.key,
value = configData.value, configData.value,
action_type = "D" action_type = "D"
}); });
var actual = JsonConvert.SerializeObject(history) as string; var actual = JsonConvert.SerializeObject(history) as string;
@ -177,10 +175,10 @@ public class SetupConfigurationTests : TestFixture
// Assert // Assert
var expected = JsonConvert.SerializeObject(new var expected = JsonConvert.SerializeObject(new
{ {
key = configData.key, configData.key,
value = configData.value, configData.value,
label = configData.label, configData.label,
content_type = configData.content_type, configData.content_type,
valid_from = ((DateTimeOffset)configData.valid_from).ToUnixTimeSeconds(), valid_from = ((DateTimeOffset)configData.valid_from).ToUnixTimeSeconds(),
expires_at = ((DateTimeOffset)configData.expires_at).ToUnixTimeSeconds() expires_at = ((DateTimeOffset)configData.expires_at).ToUnixTimeSeconds()
}); });

View file

@ -1,142 +1,144 @@
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using Shouldly;
using PlanTempus.Tests;
using PlanTempus.Core.Configurations; using PlanTempus.Core.Configurations;
using PlanTempus.Core.Configurations.JsonConfigProvider; using PlanTempus.Core.Configurations.JsonConfigProvider;
using PlanTempus.Core.Configurations.SmartConfigProvider; using PlanTempus.Core.Configurations.SmartConfigProvider;
using Shouldly;
namespace PlanTempus.Tests.ConfigurationTests namespace PlanTempus.X.TDD.ConfigurationTests;
[TestClass]
public class JsonConfigurationProviderTests : TestFixture
{ {
[TestClass] private const string _testFolder = "ConfigurationTests/";
public class JsonConfigurationProviderTests : TestFixture
public JsonConfigurationProviderTests() : base(_testFolder)
{ {
const string _testFolder = "ConfigurationTests/"; }
public JsonConfigurationProviderTests() : base(_testFolder) { }
[TestMethod] [TestMethod]
public void GetSection_ShouldReturnCorrectFeatureSection() public void GetSection_ShouldReturnCorrectFeatureSection()
{ {
// Arrange // Arrange
var expectedJObject = JObject.Parse(@"{ var expectedJObject = JObject.Parse(@"{
'Enabled': true, 'Enabled': true,
'RolloutPercentage': 25, 'RolloutPercentage': 25,
'AllowedUserGroups': ['beta'] 'AllowedUserGroups': ['beta']
}") as JToken; }") as JToken;
var builder = new ConfigurationBuilder() var builder = new ConfigurationBuilder()
.AddJsonFile($"{_testFolder}appconfiguration.dev.json") .AddJsonFile($"{_testFolder}appconfiguration.dev.json")
.Build(); .Build();
// Act // Act
var section = builder.GetSection("Feature"); var section = builder.GetSection("Feature");
// Assert // Assert
section.ShouldNotBeNull(); section.ShouldNotBeNull();
section.Value.ShouldBeEquivalentTo(expectedJObject); section.Value.ShouldBeEquivalentTo(expectedJObject);
}
[TestMethod]
public void Get_ShouldReturnCorrectFeatureObject()
{
// Arrange
var expectedFeature = new Feature
{
Enabled = true,
RolloutPercentage = 25,
AllowedUserGroups = new() { "beta" }
};
var builder = new ConfigurationBuilder()
.AddJsonFile($"{_testFolder}appconfiguration.dev.json")
.Build();
// Act
var actualFeature = builder.GetSection("Feature").ToObject<Feature>();
#pragma warning disable CS0618 // Type or member is obsolete
var actualFeatureObsoleted = builder.GetSection("Feature").Get<Feature>();
#pragma warning restore CS0618 // Type or member is obsolete
// Assert
actualFeature.ShouldBeEquivalentTo(expectedFeature);
actualFeatureObsoleted.ShouldBeEquivalentTo(expectedFeature);
}
[TestMethod]
public void Get_ShouldReturnCorrectValueAsString()
{
// Arrange
var expectedFeature = "123";
var builder = new ConfigurationBuilder()
.AddJsonFile($"{_testFolder}appconfiguration.dev.json")
.Build();
// Act
var actualFeature = builder.GetSection("AnotherSetting").Get<string>("Thresholds:High");
// Assert
actualFeature.ShouldBeEquivalentTo(expectedFeature);
}
/// <summary>
/// Testing a stupid indexer for compability with Microsoft ConfigurationBuilder
/// </summary>
[TestMethod]
public void Indexer_ShouldReturnValueAsString()
{
// Arrange
var expected = "SHA256";
var builder = new ConfigurationBuilder()
.AddJsonFile($"{_testFolder}appconfiguration.dev.json")
.Build();
// Act
var actual = builder["Authentication"];
// Assert
actual.ShouldBeEquivalentTo(expected);
}
[TestMethod]
public void Get_ShouldReturnCorrectValueAsInt()
{
// Arrange
var expectedFeature = 22;
var builder = new ConfigurationBuilder()
.AddJsonFile($"{_testFolder}appconfiguration.dev.json")
.Build();
// Act
var actualFeature = builder.GetSection("AnotherSetting:Temperature").Get<int>("Indoor:Max:Limit");
// Assert
actualFeature.ShouldBe(expectedFeature);
}
[TestMethod]
public void Get_ShouldReturnCorrectValueAsBool()
{
// Arrange
var expectedFeature = true;
var configRoot = new ConfigurationBuilder()
.AddJsonFile($"{_testFolder}appconfiguration.dev.json")
.AddSmartConfig()
.Build();
// Act
var actualFeature = configRoot.Get<bool>("Database:UseSSL");
// Assert
actualFeature.ShouldBe(expectedFeature);
}
} }
internal class Feature [TestMethod]
public void Get_ShouldReturnCorrectFeatureObject()
{ {
public bool Enabled { get; set; } // Arrange
public int RolloutPercentage { get; set; } var expectedFeature = new Feature
public List<string> AllowedUserGroups { get; set; } {
Enabled = true,
RolloutPercentage = 25,
AllowedUserGroups = new List<string> { "beta" }
};
var builder = new ConfigurationBuilder()
.AddJsonFile($"{_testFolder}appconfiguration.dev.json")
.Build();
// Act
var actualFeature = builder.GetSection("Feature").ToObject<Feature>();
#pragma warning disable CS0618 // Type or member is obsolete
var actualFeatureObsoleted = builder.GetSection("Feature").Get<Feature>();
#pragma warning restore CS0618 // Type or member is obsolete
// Assert
actualFeature.ShouldBeEquivalentTo(expectedFeature);
actualFeatureObsoleted.ShouldBeEquivalentTo(expectedFeature);
} }
[TestMethod]
public void Get_ShouldReturnCorrectValueAsString()
{
// Arrange
var expectedFeature = "123";
var builder = new ConfigurationBuilder()
.AddJsonFile($"{_testFolder}appconfiguration.dev.json")
.Build();
// Act
var actualFeature = builder.GetSection("AnotherSetting").Get<string>("Thresholds:High");
// Assert
actualFeature.ShouldBeEquivalentTo(expectedFeature);
}
/// <summary>
/// Testing a stupid indexer for compability with Microsoft ConfigurationBuilder
/// </summary>
[TestMethod]
public void Indexer_ShouldReturnValueAsString()
{
// Arrange
var expected = "SHA256";
var builder = new ConfigurationBuilder()
.AddJsonFile($"{_testFolder}appconfiguration.dev.json")
.Build();
// Act
var actual = builder["Authentication"];
// Assert
actual.ShouldBeEquivalentTo(expected);
}
[TestMethod]
public void Get_ShouldReturnCorrectValueAsInt()
{
// Arrange
var expectedFeature = 22;
var builder = new ConfigurationBuilder()
.AddJsonFile($"{_testFolder}appconfiguration.dev.json")
.Build();
// Act
var actualFeature = builder.GetSection("AnotherSetting:Temperature").Get<int>("Indoor:Max:Limit");
// Assert
actualFeature.ShouldBe(expectedFeature);
}
[TestMethod]
public void Get_ShouldReturnCorrectValueAsBool()
{
// Arrange
var expectedFeature = true;
var configRoot = new ConfigurationBuilder()
.AddJsonFile($"{_testFolder}appconfiguration.dev.json")
.AddSmartConfig()
.Build();
// Act
var actualFeature = configRoot.Get<bool>("Database:UseSSL");
// Assert
actualFeature.ShouldBe(expectedFeature);
}
}
internal class Feature
{
public bool Enabled { get; set; }
public int RolloutPercentage { get; set; }
public List<string> AllowedUserGroups { get; set; }
} }

View file

@ -1,8 +1,7 @@
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using PlanTempus.Core.Configurations.Common; using PlanTempus.Core.Configurations.Common;
using PlanTempus.Tests;
namespace PlanTempus.Tests.ConfigurationTests; namespace PlanTempus.X.TDD.ConfigurationTests;
[TestClass] [TestClass]
public class ConfigurationTests : TestFixture public class ConfigurationTests : TestFixture
@ -17,31 +16,31 @@ public class ConfigurationTests : TestFixture
public void ConfigurationSettingsTest() public void ConfigurationSettingsTest()
{ {
var pairs = new List<KeyValuePair<string, JToken>> var pairs = new List<KeyValuePair<string, JToken>>
{ {
new("Debug", true), new("Debug", true),
// Database konfiguration // Database konfiguration
new("Database:ConnectionString", "Server=db.example.com;Port=5432"), new("Database:ConnectionString", "Server=db.example.com;Port=5432"),
new("Database:Timeout", 30), new("Database:Timeout", 30),
new("Database:UseSSL", true), new("Database:UseSSL", true),
// Logging konfiguration med JObject // Logging konfiguration med JObject
new("Logging:FileOptions", JObject.Parse(@"{ new("Logging:FileOptions", JObject.Parse(@"{
'Path': '/var/logs/app.log', 'Path': '/var/logs/app.log',
'MaxSizeMB': 100, 'MaxSizeMB': 100,
'RetentionDays': 7 'RetentionDays': 7
}")), }")),
// Feature flags med kompleks konfiguration // Feature flags med kompleks konfiguration
new("Features:Experimental", JObject.Parse(@"{ new("Features:Experimental", JObject.Parse(@"{
'Enabled': true, 'Enabled': true,
'RolloutPercentage': 25, 'RolloutPercentage': 25,
'AllowedUserGroups': ['beta'] 'AllowedUserGroups': ['beta']
}")), }")),
// API endpoints med array // API endpoints med array
new("API:Endpoints", "/api/users"), new("API:Endpoints", "/api/users"),
new("API:Endpoints", "/api/products") new("API:Endpoints", "/api/products")
}; };
var result = KeyValueToJson.Convert(pairs); var result = KeyValueToJson.Convert(pairs);

View file

@ -1,86 +1,82 @@
using Autofac; using Autofac;
using Shouldly;
using System.Data;
using Insight.Database; using Insight.Database;
using PlanTempus.Core.Configurations; using PlanTempus.Core.Configurations;
using PlanTempus.Core.Configurations.JsonConfigProvider; using PlanTempus.Core.Configurations.JsonConfigProvider;
using PlanTempus.Core.Configurations.SmartConfigProvider; using PlanTempus.Core.Configurations.SmartConfigProvider;
using PlanTempus.Core.Sql.ConnectionFactory; using PlanTempus.Core.Sql.ConnectionFactory;
using Shouldly;
namespace PlanTempus.Tests.ConfigurationTests namespace PlanTempus.X.TDD.ConfigurationTests;
[TestClass]
public class SmartConfigProviderTests : TestFixture
{ {
[TestClass] private const string _testFolder = "ConfigurationTests/";
public class SmartConfigProviderTests : TestFixture
{
const string _testFolder = "ConfigurationTests/";
[TestMethod] [TestMethod]
public void TrySmartConfigWithOptionsForPostgres() public void TrySmartConfigWithOptionsForPostgres()
{ {
var config = new ConfigurationBuilder() var config = new ConfigurationBuilder()
.AddJsonFile($"{_testFolder}appconfiguration.dev.json") .AddJsonFile($"{_testFolder}appconfiguration.dev.json")
.AddSmartConfig(options => options.UsePostgres("DefaultConnection")) .AddSmartConfig(options => options.UsePostgres("DefaultConnection"))
.Build(); .Build();
var actualFeature = config.Get<bool>("Database:UseSSL"); var actualFeature = config.Get<bool>("Database:UseSSL");
}
} [TestMethod]
public void Get_ShouldReturnCorrectValueAsBool()
{
// Arrange
var expectedFeature = true;
[TestMethod] var config = new ConfigurationBuilder()
public void Get_ShouldReturnCorrectValueAsBool() .AddJsonFile($"{_testFolder}appconfiguration.dev.json")
{ .AddSmartConfig(options => options.UsePostgres("DefaultConnection"))
// Arrange .Build();
var expectedFeature = true;
var config = new ConfigurationBuilder() // Act
.AddJsonFile($"{_testFolder}appconfiguration.dev.json") var actualFeature = config.Get<bool>("Database:UseSSL");
.AddSmartConfig(options => options.UsePostgres("DefaultConnection"))
.Build();
// Act // Assert
var actualFeature = config.Get<bool>("Database:UseSSL"); actualFeature.ShouldBe(expectedFeature);
}
// Assert [TestMethod]
actualFeature.ShouldBe(expectedFeature); public void Get_ShouldReturnCorrectValueWhenSelectingIntoValueRowInConfigTable()
} {
[TestMethod] // Arrange
public void Get_ShouldReturnCorrectValueWhenSelectingIntoValueRowInConfigTable() var expectedFeature = 100;
{
// Arrange
var expectedFeature = 100;
var builder = new ConfigurationBuilder() var builder = new ConfigurationBuilder()
.AddJsonFile($"{_testFolder}appconfiguration.dev.json") .AddJsonFile($"{_testFolder}appconfiguration.dev.json")
.AddSmartConfig(options => options.UsePostgres("DefaultConnection")) .AddSmartConfig(options => options.UsePostgres("DefaultConnection"))
.Build(); .Build();
// Act // Act
var actualFeature = builder.GetSection("Logging:FileOptions").Get<int>("MaxSizeMB"); var actualFeature = builder.GetSection("Logging:FileOptions").Get<int>("MaxSizeMB");
var withoutSectionThisAlsoWorks = builder.Get<int>("Logging:FileOptions:MaxSizeMB"); var withoutSectionThisAlsoWorks = builder.Get<int>("Logging:FileOptions:MaxSizeMB");
// Assert // Assert
actualFeature.ShouldBe(expectedFeature); actualFeature.ShouldBe(expectedFeature);
actualFeature.ShouldBe(withoutSectionThisAlsoWorks); actualFeature.ShouldBe(withoutSectionThisAlsoWorks);
}
} [TestMethod]
public void TryGetActiveConfigurations()
{
var connFactory = Container.Resolve<IDbConnectionFactory>();
[TestMethod] const string sql = @"
public void TryGetActiveConfigurations()
{
var connFactory = Container.Resolve<IDbConnectionFactory>();
const string sql = @"
SELECT id, ""key"", value, label, content_type, SELECT id, ""key"", value, label, content_type,
valid_from, expires_at, created_at, modified_at, etag valid_from, expires_at, created_at, modified_at, etag
FROM app_configuration FROM app_configuration
WHERE CURRENT_TIMESTAMP BETWEEN valid_from AND expires_at WHERE CURRENT_TIMESTAMP BETWEEN valid_from AND expires_at
OR (valid_from IS NULL AND expires_at IS NULL)"; OR (valid_from IS NULL AND expires_at IS NULL)";
using (var conn = connFactory.Create()) using (var conn = connFactory.Create())
{ {
var result = conn.QuerySql(sql); var result = conn.QuerySql(sql);
}
} }
}
}
} }

View file

@ -16,23 +16,31 @@
"Feature": { "Feature": {
"Enabled": true, "Enabled": true,
"RolloutPercentage": 25, "RolloutPercentage": 25,
"AllowedUserGroups": [ "beta" ] "AllowedUserGroups": [
"beta"
]
}, },
"AnotherSetting": { "AnotherSetting": {
"Thresholds": { "Thresholds": {
"High": "123", "High": "123",
"Low": "-1" "Low": "-1"
}, },
"Temperature": { "Temperature": {
"Indoor": { "Indoor": {
"Max": { "Limit": 22 }, "Max": {
"Min": { "Limit": 18 } "Limit": 22
},
"Min": {
"Limit": 18
}
}, },
"Outdoor": { "Outdoor": {
"Max": { "Limit": 12 }, "Max": {
"Min": { "Limit": 9 } "Limit": 12
},
"Min": {
"Limit": 9
}
} }
} }
}, },

View file

@ -1,3 +1,4 @@
using System.Net;
using Autofac; using Autofac;
using Microsoft.ApplicationInsights; using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.Channel; using Microsoft.ApplicationInsights.Channel;
@ -5,67 +6,66 @@ using Microsoft.ApplicationInsights.DataContracts;
using PlanTempus.Core.Logging; using PlanTempus.Core.Logging;
using PlanTempus.Core.Telemetry; using PlanTempus.Core.Telemetry;
namespace PlanTempus.Tests.Logging namespace PlanTempus.X.TDD.Logging;
[TestClass]
public class SeqBackgroundServiceTest : TestFixture
{ {
[TestClass] private CancellationTokenSource _cts;
public class SeqBackgroundServiceTest : TestFixture private IMessageChannel<ITelemetry> _messageChannel;
private SeqBackgroundService _service;
[TestInitialize]
public void SetupThis()
{ {
private IMessageChannel<ITelemetry> _messageChannel; _messageChannel = new MessageChannel();
private SeqBackgroundService _service; var telemetryClient = Container.Resolve<TelemetryClient>();
private CancellationTokenSource _cts;
[TestInitialize] var config = new SeqConfiguration("http://localhost:5341", null, "MSTEST");
public void SetupThis()
var httpClient = new SeqHttpClient(config);
var logger = new SeqLogger<SeqBackgroundService>(httpClient, config);
_service = new SeqBackgroundService(telemetryClient, _messageChannel, logger);
_cts = new CancellationTokenSource();
}
[TestMethod]
public async Task Messages_ShouldBeProcessedFromQueue()
{
await _service.StartAsync(_cts.Token);
for (var i = 0; i < 5; i++)
{ {
_messageChannel = new MessageChannel(); var eventTelemetry = new EventTelemetry
var telemetryClient = Container.Resolve<TelemetryClient>(); {
Name = "Test Event",
Timestamp = DateTimeOffset.UtcNow
};
eventTelemetry.Properties.Add("TestId", Guid.NewGuid().ToString());
eventTelemetry.Metrics.Add("TestMetric", 42.0);
var config = new SeqConfiguration("http://localhost:5341", null, "MSTEST"); await _messageChannel.Writer.WriteAsync(eventTelemetry);
var httpClient = new SeqHttpClient(config);
var logger = new SeqLogger<SeqBackgroundService>(httpClient, config);
_service = new SeqBackgroundService(telemetryClient, _messageChannel, logger);
_cts = new CancellationTokenSource();
} }
[TestMethod] // wait for processing
public async Task Messages_ShouldBeProcessedFromQueue() await Task.Delay(5000);
_cts.Cancel(); //not sure about this, we need to analyse more before this is "the way"
await _service.StopAsync(CancellationToken.None);
var hasMoreMessages = await _messageChannel.Reader.WaitToReadAsync();
Assert.IsFalse(hasMoreMessages, "Queue should be empty after 5 seconds");
}
private class TestMessageHandler : HttpMessageHandler
{
protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{ {
await _service.StartAsync(_cts.Token); return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK));
for (int i = 0; i < 5; i++)
{
var eventTelemetry = new EventTelemetry
{
Name = "Test Event",
Timestamp = DateTimeOffset.UtcNow
};
eventTelemetry.Properties.Add("TestId", Guid.NewGuid().ToString());
eventTelemetry.Metrics.Add("TestMetric", 42.0);
await _messageChannel.Writer.WriteAsync(eventTelemetry);
}
// wait for processing
await Task.Delay(5000);
_cts.Cancel(); //not sure about this, we need to analyse more before this is "the way"
await _service.StopAsync(CancellationToken.None);
bool hasMoreMessages = await _messageChannel.Reader.WaitToReadAsync();
Assert.IsFalse(hasMoreMessages, "Queue should be empty after 5 seconds");
}
private class TestMessageHandler : HttpMessageHandler
{
protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
return Task.FromResult(new HttpResponseMessage(System.Net.HttpStatusCode.OK));
}
} }
} }
} }

View file

@ -3,146 +3,143 @@ using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.DataContracts; using Microsoft.ApplicationInsights.DataContracts;
using PlanTempus.Core.Logging; using PlanTempus.Core.Logging;
namespace PlanTempus.Tests.Logging namespace PlanTempus.X.TDD.Logging;
[TestClass]
public class SeqLoggerTests : TestFixture
{ {
[TestClass] private readonly string _testId;
public class SeqLoggerTests : TestFixture private readonly SeqHttpClient _httpClient;
private readonly SeqLogger<SeqLoggerTests> _logger;
public SeqLoggerTests()
{ {
private SeqLogger<SeqLoggerTests> _logger; _testId = Guid.NewGuid().ToString();
private SeqHttpClient _httpClient; var config = new SeqConfiguration("http://localhost:5341", null, "MSTEST");
private readonly string _testId; _httpClient = new SeqHttpClient(config);
_logger = new SeqLogger<SeqLoggerTests>(_httpClient, config);
}
public SeqLoggerTests() [TestMethod]
public async Task LogTraceTelemetry_SendsCorrectDataWithErrorLevel()
{
// Arrange
var traceTelemetry = new TraceTelemetry
{ {
_testId = Guid.NewGuid().ToString(); Message = "Test trace error message",
var config = new SeqConfiguration("http://localhost:5341", null, "MSTEST"); SeverityLevel = SeverityLevel.Error,
_httpClient = new SeqHttpClient(config); Timestamp = DateTimeOffset.UtcNow
_logger = new SeqLogger<SeqLoggerTests>(_httpClient, config); };
} traceTelemetry.Properties.Add("TestId", _testId);
[TestMethod] // Act
public async Task LogTraceTelemetry_SendsCorrectDataWithErrorLevel() await _logger.LogAsync(traceTelemetry);
}
[TestMethod]
public async Task LogTraceTelemetry_SendsCorrectDataWithWarningLevel()
{
// Arrange
var traceTelemetry = new TraceTelemetry
{
Message = "Test trace warning message",
SeverityLevel = SeverityLevel.Warning,
Timestamp = DateTimeOffset.UtcNow
};
traceTelemetry.Properties.Add("TestId", _testId);
// Act
await _logger.LogAsync(traceTelemetry);
}
[TestMethod]
public async Task LogEventTelemetry_SendsCorrectData()
{
// Arrange
var eventTelemetry = new EventTelemetry
{
Name = "Test Event",
Timestamp = DateTimeOffset.UtcNow
};
eventTelemetry.Properties.Add("TestId", _testId);
eventTelemetry.Metrics.Add("TestMetric", 42.0);
// Act
await _logger.LogAsync(eventTelemetry);
}
[TestMethod]
public async Task LogExceptionTelemetry_SendsCorrectData()
{
try
{
var t = 0;
var result = 10 / t;
}
catch (Exception e)
{ {
// Arrange // Arrange
var traceTelemetry = new TraceTelemetry var exceptionTelemetry = new ExceptionTelemetry(e)
{ {
Message = "Test trace error message",
SeverityLevel = SeverityLevel.Error,
Timestamp = DateTimeOffset.UtcNow Timestamp = DateTimeOffset.UtcNow
}; };
traceTelemetry.Properties.Add("TestId", _testId); exceptionTelemetry.Properties.Add("TestId", _testId);
// Act // Act
await _logger.LogAsync(traceTelemetry); await _logger.LogAsync(exceptionTelemetry);
} }
[TestMethod] }
public async Task LogTraceTelemetry_SendsCorrectDataWithWarningLevel()
[TestMethod]
public async Task LogDependencyTelemetry_SendsCorrectData()
{
// Arrange
var dependencyTelemetry = new DependencyTelemetry
{ {
// Arrange Name = "SQL Query",
var traceTelemetry = new TraceTelemetry Type = "SQL",
{ Target = "TestDB",
Message = "Test trace warning message", Success = true,
SeverityLevel = SeverityLevel.Warning, Duration = TimeSpan.FromMilliseconds(100),
Timestamp = DateTimeOffset.UtcNow Timestamp = DateTimeOffset.UtcNow
}; };
traceTelemetry.Properties.Add("TestId", _testId); dependencyTelemetry.Properties.Add("TestId", _testId);
// Act // Act
await _logger.LogAsync(traceTelemetry); await _logger.LogAsync(dependencyTelemetry);
}
} /// <summary>
[TestMethod] /// This is for scope test in SeqLogger. It is not testing anything related to the TelemetryChannel which logs to Seq.
public async Task LogEventTelemetry_SendsCorrectData() /// </summary>
/// <returns></returns>
[TestMethod]
public async Task LogRequestTelemetryInOperationHolderWithParentChild_SendsCorrectData()
{
var telemetryClient = Container.Resolve<TelemetryClient>();
using (var parent = telemetryClient.StartOperation<RequestTelemetry>("Parent First"))
{ {
// Arrange parent.Telemetry.Duration = TimeSpan.FromMilliseconds(250);
var eventTelemetry = new EventTelemetry parent.Telemetry.Url = new Uri("http://parent.test.com/api/test");
using (var child = telemetryClient.StartOperation<RequestTelemetry>("Child 1"))
{ {
Name = "Test Event", child.Telemetry.Success = true;
Timestamp = DateTimeOffset.UtcNow child.Telemetry.ResponseCode = "200";
}; child.Telemetry.Duration = TimeSpan.FromMilliseconds(50);
eventTelemetry.Properties.Add("TestId", _testId); child.Telemetry.Url = new Uri("http://child.test.com/api/test");
eventTelemetry.Metrics.Add("TestMetric", 42.0); child.Telemetry.Timestamp = DateTimeOffset.UtcNow;
// Act child.Telemetry.Properties.Add("httpMethod", HttpMethod.Get.ToString());
await _logger.LogAsync(eventTelemetry); child.Telemetry.Properties.Add("TestId", _testId);
}
[TestMethod]
public async Task LogExceptionTelemetry_SendsCorrectData()
{
try
{
int t = 0;
var result = 10 / t;
await _logger.LogAsync(child);
} }
catch (Exception e)
{
// Arrange ;
var exceptionTelemetry = new ExceptionTelemetry(e)
{
Timestamp = DateTimeOffset.UtcNow
};
exceptionTelemetry.Properties.Add("TestId", _testId);
// Act await _logger.LogAsync(parent);
await _logger.LogAsync(exceptionTelemetry);
}
}
[TestMethod]
public async Task LogDependencyTelemetry_SendsCorrectData()
{
// Arrange
var dependencyTelemetry = new DependencyTelemetry
{
Name = "SQL Query",
Type = "SQL",
Target = "TestDB",
Success = true,
Duration = TimeSpan.FromMilliseconds(100),
Timestamp = DateTimeOffset.UtcNow
};
dependencyTelemetry.Properties.Add("TestId", _testId);
// Act
await _logger.LogAsync(dependencyTelemetry);
}
/// <summary>
/// This is for scope test in SeqLogger. It is not testing anything related to the TelemetryChannel which logs to Seq.
/// </summary>
/// <returns></returns>
[TestMethod]
public async Task LogRequestTelemetryInOperationHolderWithParentChild_SendsCorrectData()
{
var telemetryClient = Container.Resolve<TelemetryClient>();
using (Microsoft.ApplicationInsights.Extensibility.IOperationHolder<RequestTelemetry> parent = telemetryClient.StartOperation<RequestTelemetry>("Parent First"))
{
parent.Telemetry.Duration = TimeSpan.FromMilliseconds(250);
parent.Telemetry.Url = new Uri("http://parent.test.com/api/test");
using (var child = telemetryClient.StartOperation<RequestTelemetry>("Child 1"))
{
child.Telemetry.Success = true;
child.Telemetry.ResponseCode = "200";
child.Telemetry.Duration = TimeSpan.FromMilliseconds(50);
child.Telemetry.Url = new Uri("http://child.test.com/api/test");
child.Telemetry.Timestamp = DateTimeOffset.UtcNow;
child.Telemetry.Properties.Add("httpMethod", HttpMethod.Get.ToString());
child.Telemetry.Properties.Add("TestId", _testId);
await _logger.LogAsync(child);
};
await _logger.LogAsync(parent);
}
} }
} }
} }

View file

@ -5,57 +5,56 @@ using Microsoft.ApplicationInsights.DataContracts;
using PlanTempus.Core.Logging; using PlanTempus.Core.Logging;
using PlanTempus.Core.Telemetry; using PlanTempus.Core.Telemetry;
namespace PlanTempus.Tests.Logging namespace PlanTempus.X.TDD.Logging;
[TestClass]
public class SeqTelemetryChannelTest : TestFixture
{ {
[TestClass] private CancellationTokenSource _cts;
public class SeqTelemetryChannelTest : TestFixture private IMessageChannel<ITelemetry> _messageChannel;
private SeqBackgroundService _service;
private TelemetryClient _telemetryClient;
[TestInitialize]
public void SetupThis()
{ {
private IMessageChannel<ITelemetry> _messageChannel; //it is important to use the same MessageChannel as the BackgroundService uses
TelemetryClient _telemetryClient; //we know that IMessageChannel<ITelemetry> _messageChannel; is registered via Autofac and manually injected into SeqBackgroundService
private SeqBackgroundService _service; //so we can get it by calling the Autofac Container in this test.
private CancellationTokenSource _cts;
[TestInitialize] _messageChannel = Container.Resolve<IMessageChannel<ITelemetry>>();
public void SetupThis() _service = Container.Resolve<SeqBackgroundService>();
_telemetryClient = Container.Resolve<TelemetryClient>();
_cts = new CancellationTokenSource();
}
[TestMethod]
public async Task Messages_ShouldBeProcessedFromQueue()
{
await _service.StartAsync(_cts.Token);
for (var i = 0; i < 5; i++)
{ {
//it is important to use the same MessageChannel as the BackgroundService uses var eventTelemetry = new EventTelemetry
//we know that IMessageChannel<ITelemetry> _messageChannel; is registered via Autofac and manually injected into SeqBackgroundService
//so we can get it by calling the Autofac Container in this test.
_messageChannel = Container.Resolve<IMessageChannel<ITelemetry>>();
_service = Container.Resolve<SeqBackgroundService>();
_telemetryClient = Container.Resolve<TelemetryClient>();
_cts = new CancellationTokenSource();
}
[TestMethod]
public async Task Messages_ShouldBeProcessedFromQueue()
{
await _service.StartAsync(_cts.Token);
for (int i = 0; i < 5; i++)
{ {
var eventTelemetry = new EventTelemetry Name = "Test Event 3",
{ Timestamp = DateTimeOffset.UtcNow
Name = "Test Event 3", };
Timestamp = DateTimeOffset.UtcNow
};
eventTelemetry.Properties.Add("TestId", Guid.NewGuid().ToString()); eventTelemetry.Properties.Add("TestId", Guid.NewGuid().ToString());
eventTelemetry.Metrics.Add("TestMetric", 42.0); eventTelemetry.Metrics.Add("TestMetric", 42.0);
//we don't write to the _messageChannel.Writer.WriteAsync(eventTelemetry);, but the TelemetryClient which is configured to use SeqTelemetryChannel //we don't write to the _messageChannel.Writer.WriteAsync(eventTelemetry);, but the TelemetryClient which is configured to use SeqTelemetryChannel
_telemetryClient.TrackEvent(eventTelemetry); _telemetryClient.TrackEvent(eventTelemetry);
}
// wait for processing
await Task.Delay(5000);
await _service.StopAsync(CancellationToken.None);
bool hasMoreMessages = await _messageChannel.Reader.WaitToReadAsync();
Assert.IsFalse(hasMoreMessages, "Queue should be empty after 5 seconds");
} }
// wait for processing
await Task.Delay(5000);
await _service.StopAsync(CancellationToken.None);
var hasMoreMessages = await _messageChannel.Reader.WaitToReadAsync();
Assert.IsFalse(hasMoreMessages, "Queue should be empty after 5 seconds");
} }
} }

View file

@ -1,89 +1,87 @@
using System.Diagnostics; using System.Diagnostics;
using Sodium; using System.Text;
using PlanTempus.Core; using PlanTempus.Core;
using Sodium;
namespace PlanTempus.Tests namespace PlanTempus.X.TDD;
[TestClass]
public class PasswordHasherTests : TestFixture
{ {
[TestClass] [TestMethod]
public class PasswordHasherTests : TestFixture public void MyTestMethod()
{ {
var stopwatch = Stopwatch.StartNew();
[TestMethod] var salt = PasswordHash.ScryptGenerateSalt();
public void MyTestMethod()
{
var stopwatch = Stopwatch.StartNew();
byte[] salt = PasswordHash.ScryptGenerateSalt(); // 2. Konverter password til byte[]
var passwordBytes = Encoding.UTF8.GetBytes("password123");
// 2. Konverter password til byte[] // 3. Kald ScryptHashBinary korrekt
byte[] passwordBytes = System.Text.Encoding.UTF8.GetBytes("password123"); var hash = PasswordHash.ScryptHashBinary(
passwordBytes,
salt
);
// 3. Kald ScryptHashBinary korrekt stopwatch.Stop();
byte[] hash = PasswordHash.ScryptHashBinary( }
password: passwordBytes,
salt: salt, // 32-byte array
limit: PasswordHash.Strength.Interactive,
outputLength: 32
);
stopwatch.Stop(); [TestMethod]
} public void HashPassword_ShouldCreateValidHashFormat()
[TestMethod] {
public void HashPassword_ShouldCreateValidHashFormat() // Arrange
{ var password = "TestPassword123";
// Arrange
string password = "TestPassword123";
// Act // Act
string hashedPassword = new SecureTokenizer().TokenizeText(password); var hashedPassword = new SecureTokenizer().TokenizeText(password);
string[] parts = hashedPassword.Split('.'); var parts = hashedPassword.Split('.');
// Assert // Assert
Assert.AreEqual(3, parts.Length); Assert.AreEqual(3, parts.Length);
Assert.AreEqual("100000", parts[0]); Assert.AreEqual("100000", parts[0]);
} }
[TestMethod] [TestMethod]
public void VerifyPassword_WithCorrectPassword_ShouldReturnTrue() public void VerifyPassword_WithCorrectPassword_ShouldReturnTrue()
{ {
// Arrange // Arrange
string password = "TestPassword123"; var password = "TestPassword123";
string hashedPassword = new SecureTokenizer().TokenizeText(password); var hashedPassword = new SecureTokenizer().TokenizeText(password);
// Act // Act
bool result = new SecureTokenizer().VerifyToken(hashedPassword, password); var result = new SecureTokenizer().VerifyToken(hashedPassword, password);
// Assert // Assert
Assert.IsTrue(result); Assert.IsTrue(result);
} }
[TestMethod] [TestMethod]
public void VerifyPassword_WithWrongPassword_ShouldReturnFalse() public void VerifyPassword_WithWrongPassword_ShouldReturnFalse()
{ {
// Arrange // Arrange
string correctPassword = "TestPassword123"; var correctPassword = "TestPassword123";
string wrongPassword = "WrongPassword123"; var wrongPassword = "WrongPassword123";
string hashedPassword = new SecureTokenizer().TokenizeText(correctPassword); var hashedPassword = new SecureTokenizer().TokenizeText(correctPassword);
// Act // Act
bool result = new SecureTokenizer().VerifyToken(hashedPassword, wrongPassword); var result = new SecureTokenizer().VerifyToken(hashedPassword, wrongPassword);
// Assert // Assert
Assert.IsFalse(result); Assert.IsFalse(result);
} }
[TestMethod] [TestMethod]
public void VerifyPassword_WithInvalidHashFormat_ShouldReturnFalse() public void VerifyPassword_WithInvalidHashFormat_ShouldReturnFalse()
{ {
// Arrange // Arrange
string password = "TestPassword123"; var password = "TestPassword123";
string invalidHash = "InvalidHash"; var invalidHash = "InvalidHash";
// Act // Act
bool result = new SecureTokenizer().VerifyToken(invalidHash, password); var result = new SecureTokenizer().VerifyToken(invalidHash, password);
// Assert // Assert
Assert.IsFalse(result); Assert.IsFalse(result);
}
} }
} }

View file

@ -1,41 +1,41 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject> <IsTestProject>true</IsTestProject>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.0" /> <PackageReference Include="coverlet.collector" Version="6.0.0"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0"/>
<PackageReference Include="moq" Version="4.20.72" /> <PackageReference Include="moq" Version="4.20.72"/>
<PackageReference Include="MSTest.TestAdapter" Version="3.1.1" /> <PackageReference Include="MSTest.TestAdapter" Version="3.1.1"/>
<PackageReference Include="MSTest.TestFramework" Version="3.1.1" /> <PackageReference Include="MSTest.TestFramework" Version="3.1.1"/>
<PackageReference Include="Shouldly" Version="4.3.0" /> <PackageReference Include="Shouldly" Version="4.3.0"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Application\PlanTempus.Application.csproj" /> <ProjectReference Include="..\Application\PlanTempus.Application.csproj"/>
<ProjectReference Include="..\Database\PlanTempus.Database.csproj" /> <ProjectReference Include="..\Database\PlanTempus.Database.csproj"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Using Include="Microsoft.VisualStudio.TestTools.UnitTesting" /> <Using Include="Microsoft.VisualStudio.TestTools.UnitTesting"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Update="appconfiguration.dev.json"> <None Update="appconfiguration.dev.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
<None Update="ConfigurationTests\appconfiguration.dev.json"> <None Update="ConfigurationTests\appconfiguration.dev.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
<None Update="ConfigurationTests\appconfiguration.dev.json"> <None Update="ConfigurationTests\appconfiguration.dev.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -1,95 +1,137 @@
using Autofac; using Autofac;
using System.Data;
using Insight.Database; using Insight.Database;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PlanTempus.Core.Sql.ConnectionFactory;
using PlanTempus.Core.Sql; using PlanTempus.Core.Sql;
using PlanTempus.Core.Sql.ConnectionFactory;
using Shouldly;
namespace PlanTempus.Tests namespace PlanTempus.X.TDD;
[TestClass]
public class PostgresTests : TestFixture
{ {
[TestClass] private IDbConnectionFactory _connFactory;
public class PostgresTests : TestFixture private IDatabaseOperations _databaseOperations;
[TestInitialize]
public void MyTestMethod()
{ {
IDbConnectionFactory _connFactory; _connFactory = Container.Resolve<IDbConnectionFactory>();
IDatabaseOperations _databaseOperations; _databaseOperations = Container.Resolve<IDatabaseOperations>();
}
[TestInitialize] [TestMethod]
public void MyTestMethod() public void TestDefaultConnection()
{
//https://stackoverflow.com/questions/69169247/how-to-create-idbconnection-factory-using-autofac-for-dapper
using (var conn = _connFactory.Create())
{ {
_connFactory = Container.Resolve<IDbConnectionFactory>(); conn.ExecuteSql("SELECT 1 as p");
_databaseOperations = Container.Resolve<IDatabaseOperations>();
}
[TestMethod]
public void TestDefaultConnection()
{
//https://stackoverflow.com/questions/69169247/how-to-create-idbconnection-factory-using-autofac-for-dapper
using (var conn = _connFactory.Create())
conn.ExecuteSql("SELECT 1 as p");
}
[TestMethod]
public async Task TestScopeConnectionWithLogging()
{
using var db = _databaseOperations.CreateScope(nameof(TestScopeConnectionWithLogging));
try
{
var user = await db.Connection.QuerySqlAsync<string>(
"SELECT tablename FROM pg_tables limit 5");
db.Success();
}
catch (Exception ex)
{
db.Error(ex);
throw;
}
}
[TestMethod]
public async Task TestScopeConnectionWithErrorLogging()
{
using var db = _databaseOperations.CreateScope(nameof(TestScopeConnectionWithLogging));
try
{
var user = await db.Connection.QuerySqlAsync<string>(
"SELECT tablename FROM pg_tabless limit 5");
db.Success();
}
catch (Exception ex)
{
db.Error(ex);
}
}
[TestMethod]
public async Task TestSimpleDatabaseOperation()
{
try
{
await _databaseOperations.ExecuteAsync(async connection =>
{
return await connection.QuerySqlAsync<string>(
"SELECT tablename FROM pg_tables limit 5");
}, nameof(TestSimpleDatabaseOperation));
}
catch (Exception ex)
{
throw;
}
}
[TestMethod]
public void SetupPostgresql_LISTEN()
{
//this is not in use a the moment... kind of premature test to get my mind in to gear
//var builder = new ConfigurationBuilder()
// .AddPostgresConfiguration(options =>
// {
// options.ConnectionString = "Host=192.168.1.57;Database=ptdb01;Username=postgres;Password=3911";
// options.Channel = "config_changes";
// options.ConfigurationQuery = @"select * from dev.app_configuration";
// });
} }
} }
[TestMethod]
public async Task TestScopeConnectionWithLogging()
{
using var db = _databaseOperations.CreateScope(nameof(TestScopeConnectionWithLogging));
try
{
var user = await db.Connection.QuerySqlAsync<string>(
"SELECT tablename FROM pg_tables limit 5");
db.Success();
}
catch (Exception ex)
{
db.Error(ex);
throw;
}
}
[TestMethod]
public async Task TestScopeConnectionWithErrorLogging()
{
using var db = _databaseOperations.CreateScope(nameof(TestScopeConnectionWithLogging));
try
{
var user = await db.Connection.QuerySqlAsync<string>(
"SELECT tablename FROM pg_tables limit 5");
db.Success();
}
catch (Exception ex)
{
db.Error(ex);
}
}
[TestMethod]
public async Task TestForUniqueUserEmail()
{
using var db = _databaseOperations.CreateScope(nameof(TestForUniqueUserEmail));
try
{
var sql = @"
INSERT INTO system.users(email, password_hash, security_stamp, email_confirmed,
access_failed_count, lockout_enabled,
is_active)
VALUES(@Email, @PasswordHash, @SecurityStamp, @EmailConfirmed,
@AccessFailedCount, @LockoutEnabled, @IsActive)
RETURNING id, created_at, email, is_active";
var parameters = new
{
Email = "elon.musk@mars.com",
PasswordHash = "MartianRover2025",
SecurityStamp = "MarsOrBust",
EmailConfirmed = true,
AccessFailedCount = 0,
LockoutEnabled = false,
IsActive = true
};
var user = await db.Connection.QuerySqlAsync<dynamic>(sql, parameters);
user.ShouldNotBeNull();
// ((string)user.email).ShouldBe("elon.musk@mars.com");
// ((bool)user.is_active).ShouldBeTrue();
db.Success();
}
catch (Exception ex)
{
db.Error(ex);
}
}
[TestMethod]
public async Task TestSimpleDatabaseOperation()
{
try
{
await _databaseOperations.ExecuteAsync(async connection =>
{
return await connection.QuerySqlAsync<string>(
"SELECT tablename FROM pg_tables limit 5");
}, nameof(TestSimpleDatabaseOperation));
}
catch (Exception ex)
{
throw;
}
}
[TestMethod]
public void SetupPostgresql_LISTEN()
{
//this is not in use a the moment... kind of premature test to get my mind in to gear
//var builder = new ConfigurationBuilder()
// .AddPostgresConfiguration(options =>
// {
// options.ConnectionString = "Host=192.168.1.57;Database=ptdb01;Username=postgres;Password=3911";
// options.Channel = "config_changes";
// options.ConfigurationQuery = @"select * from dev.app_configuration";
// });
}
} }

View file

@ -1,6 +1 @@
namespace PlanTempus.X.TDD;
namespace PlanTempus.Tests
{
}

View file

@ -1,96 +1,99 @@
using System; using System.Diagnostics;
using System.Diagnostics;
using Autofac; using Autofac;
using Microsoft.ApplicationInsights; using Microsoft.ApplicationInsights;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using PlanTempus.Core.Configurations; using PlanTempus.Core.Configurations;
using PlanTempus.Core.Configurations.JsonConfigProvider; using PlanTempus.Core.Configurations.JsonConfigProvider;
using PlanTempus.Core.Logging;
using PlanTempus.Core.ModuleRegistry; using PlanTempus.Core.ModuleRegistry;
namespace PlanTempus.Tests using PlanTempus.Database.ModuleRegistry;
namespace PlanTempus.X.TDD;
/// <summary>
/// Act as base class for tests. Avoids duplication of test setup code
/// </summary>
[TestClass]
public abstract class TestFixture
{ {
/// <summary> private readonly string _configurationFilePath;
/// Act as base class for tests. Avoids duplication of test setup code
/// </summary> protected TestFixture() : this(null)
[TestClass]
public abstract partial class TestFixture
{ {
private readonly string _configurationFilePath; }
protected IContainer Container { get; private set; } public TestFixture(string configurationFilePath)
protected ContainerBuilder ContainerBuilder { get; private set; } {
if (configurationFilePath is not null)
_configurationFilePath = configurationFilePath?.TrimEnd('/') + "/";
public virtual IConfigurationRoot Configuration() CreateContainerBuilder();
Container = ContainerBuilder.Build();
}
protected IContainer Container { get; private set; }
protected ContainerBuilder ContainerBuilder { get; private set; }
public virtual IConfigurationRoot Configuration()
{
var configuration = new ConfigurationBuilder()
.AddJsonFile($"{_configurationFilePath}appconfiguration.dev.json")
.Build();
return configuration;
}
protected virtual void CreateContainerBuilder()
{
var configuration = Configuration();
//var logger = new LoggerConfiguration()
// .MinimumLevel.Verbose()
// .MinimumLevel.Override("Microsoft", Serilog.Events.LogEventLevel.Warning)
// .MinimumLevel.Override("System", Serilog.Events.LogEventLevel.Error)
// .WriteTo.Seq("http://localhost:5341", apiKey: "Gt8hS9ClGNfOCAdswDlW")
// .WriteTo.ApplicationInsights(configuration.Get<string>("ApplicationInsights:ConnectionString"),
// TelemetryConverter.Traces)
// .Enrich.FromLogContext()
// .Enrich.WithMachineName()
// .CreateLogger();
var builder = new ContainerBuilder();
builder.RegisterGeneric(typeof(Logger<>))
.As(typeof(ILogger<>))
.SingleInstance();
builder.RegisterModule(new DbPostgreSqlModule
{ {
var configuration = new ConfigurationBuilder() ConnectionString = configuration.GetConnectionString("DefaultConnection")
.AddJsonFile($"{_configurationFilePath}appconfiguration.dev.json") });
.Build();
return configuration; builder.RegisterModule(new TelemetryModule
}
protected TestFixture() : this(null) { }
public TestFixture(string configurationFilePath)
{ {
if (configurationFilePath is not null) TelemetryConfig = configuration.GetSection("ApplicationInsights").ToObject<TelemetryConfig>()
_configurationFilePath = configurationFilePath?.TrimEnd('/') + "/"; });
builder.RegisterModule(new SeqLoggingModule
CreateContainerBuilder();
Container = ContainerBuilder.Build();
}
protected virtual void CreateContainerBuilder()
{ {
IConfigurationRoot configuration = Configuration(); SeqConfiguration = configuration.GetSection("SeqConfiguration").ToObject<SeqConfiguration>()
});
//var logger = new LoggerConfiguration()
// .MinimumLevel.Verbose()
// .MinimumLevel.Override("Microsoft", Serilog.Events.LogEventLevel.Warning)
// .MinimumLevel.Override("System", Serilog.Events.LogEventLevel.Error)
// .WriteTo.Seq("http://localhost:5341", apiKey: "Gt8hS9ClGNfOCAdswDlW")
// .WriteTo.ApplicationInsights(configuration.Get<string>("ApplicationInsights:ConnectionString"),
// TelemetryConverter.Traces)
// .Enrich.FromLogContext()
// .Enrich.WithMachineName()
// .CreateLogger();
var builder = new ContainerBuilder();
builder.RegisterGeneric(typeof(Logger<>))
.As(typeof(ILogger<>))
.SingleInstance();
builder.RegisterModule(new Database.ModuleRegistry.DbPostgreSqlModule ContainerBuilder = builder;
{ }
ConnectionString = configuration.GetConnectionString("DefaultConnection")
});
builder.RegisterModule(new TelemetryModule [TestCleanup]
{ public void CleanUp()
TelemetryConfig = configuration.GetSection("ApplicationInsights").ToObject<TelemetryConfig>() {
}); Trace.Flush();
builder.RegisterModule(new SeqLoggingModule var telemetryClient = Container.Resolve<TelemetryClient>();
{ telemetryClient.Flush();
SeqConfiguration = configuration.GetSection("SeqConfiguration").ToObject<Core.Logging.SeqConfiguration>()
}); if (Container != null)
ContainerBuilder = builder;
}
[TestCleanup]
public void CleanUp()
{ {
Trace.Flush(); Container.Dispose();
var telemetryClient = Container.Resolve<TelemetryClient>(); Container = null;
telemetryClient.Flush();
if (Container != null)
{
Container.Dispose();
Container = null;
}
} }
} }
} }