Merge pull request #5 from bimbej/tests

Basictests
This commit is contained in:
Michał Zieliński
2025-06-08 15:21:17 +02:00
committed by GitHub
10 changed files with 203 additions and 75 deletions

View File

@@ -53,11 +53,40 @@ jobs:
working-directory: src/Backend working-directory: src/Backend
run: dotnet restore DiunaBI.sln run: dotnet restore DiunaBI.sln
- name: Build solution - name: Build solution and prepare plugins
working-directory: src/Backend working-directory: src/Backend
run: dotnet build DiunaBI.sln --configuration Release --no-restore run: |
dotnet build DiunaBI.sln --configuration Release
dotnet build DiunaBI.Plugins.Morska/DiunaBI.Plugins.Morska.csproj --configuration Release
# Przygotuj katalog dla testów
mkdir -p DiunaBI.Tests/bin/Release/net8.0/Plugins
cp DiunaBI.Plugins.Morska/bin/Release/net8.0/DiunaBI.Plugins.Morska.dll DiunaBI.Tests/bin/Release/net8.0/Plugins/
cp DiunaBI.Plugins.Morska/bin/Release/net8.0/DiunaBI.Core.dll DiunaBI.Tests/bin/Release/net8.0/Plugins/
echo "✅ Plugins copied to test directory:"
ls -la DiunaBI.Tests/bin/Release/net8.0/Plugins/
- name: Run Tests
working-directory: src/Backend
run: |
dotnet add DiunaBI.Tests/DiunaBI.Tests.csproj package coverlet.collector
dotnet test DiunaBI.Tests/DiunaBI.Tests.csproj \
--configuration Release \
--no-restore \
--logger "trx;LogFileName=test-results.trx" \
--collect:"XPlat Code Coverage" \
--filter "Category!=LocalOnly"
- name: Publish Test Results
uses: actions/upload-artifact@v4
if: success() || failure()
with:
name: test-results
path: |
src/Backend/DiunaBI.Tests/TestResults/*.trx
src/Backend/DiunaBI.Tests/TestResults/**/coverage.cobertura.xml
- name: Publish WebAPI - name: Publish WebAPI
if: success()
working-directory: src/Backend working-directory: src/Backend
run: | run: |
dotnet publish DiunaBI.WebAPI/DiunaBI.WebAPI.csproj \ dotnet publish DiunaBI.WebAPI/DiunaBI.WebAPI.csproj \
@@ -65,14 +94,10 @@ jobs:
--framework net8.0 \ --framework net8.0 \
--self-contained false \ --self-contained false \
--output ../../build/webapi --output ../../build/webapi
# Kopiuj pluginy do katalogu webapi
- name: Build and copy plugins
working-directory: src/Backend
run: |
dotnet build DiunaBI.Plugins.Morska/DiunaBI.Plugins.Morska.csproj --configuration Release
mkdir -p ../../build/webapi/Plugins mkdir -p ../../build/webapi/Plugins
cp DiunaBI.Plugins.Morska/bin/Release/net8.0/DiunaBI.Plugins.Morska.dll ../../build/webapi/Plugins/ cp DiunaBI.Plugins.Morska/bin/Release/net8.0/DiunaBI.Plugins.Morska.dll ../../build/webapi/Plugins/
echo "✅ Plugins copied:" echo "✅ Plugins copied to webapi:"
ls -la ../../build/webapi/Plugins/ ls -la ../../build/webapi/Plugins/
- name: Clean up sensitive files - name: Clean up sensitive files

View File

@@ -46,21 +46,21 @@ public class PluginManager
} }
} }
_logger.LogInformation("Loaded {ProcessorCount} processors and {ImporterCount} importers from {AssemblyCount} assemblies", _logger.LogInformation("Loaded {ProcessorCount} processors and {ImporterCount} importers from {AssemblyCount} assemblies",
_processorTypes.Count, _processorTypes.Count,
_importerTypes.Count, _importerTypes.Count,
dllFiles.Length); // Zmień z _plugins.Count na assemblyFiles.Length dllFiles.Length); // Zmień z _plugins.Count na assemblyFiles.Length
} }
private void LoadPluginFromAssembly(string assemblyPath) private void LoadPluginFromAssembly(string assemblyPath)
{ {
_logger.LogDebug("Loading assembly from: {Path}", assemblyPath); // Information -> Debug _logger.LogDebug("Loading assembly from: {Path}", assemblyPath); // Information -> Debug
try try
{ {
var assembly = Assembly.LoadFrom(assemblyPath); var assembly = Assembly.LoadFrom(assemblyPath);
_logger.LogDebug("Assembly loaded successfully: {Name}", assembly.FullName); // Information -> Debug _logger.LogDebug("Assembly loaded successfully: {Name}", assembly.FullName); // Information -> Debug
foreach (var type in assembly.GetTypes()) foreach (var type in assembly.GetTypes())
{ {
if (typeof(IDataProcessor).IsAssignableFrom(type) && !type.IsInterface && !type.IsAbstract) if (typeof(IDataProcessor).IsAssignableFrom(type) && !type.IsInterface && !type.IsAbstract)
@@ -68,7 +68,7 @@ public class PluginManager
_processorTypes.Add(type); _processorTypes.Add(type);
_logger.LogDebug("Registered processor: {Type}", type.Name); // Information -> Debug _logger.LogDebug("Registered processor: {Type}", type.Name); // Information -> Debug
} }
if (typeof(IDataImporter).IsAssignableFrom(type) && !type.IsInterface && !type.IsAbstract) if (typeof(IDataImporter).IsAssignableFrom(type) && !type.IsInterface && !type.IsAbstract)
{ {
_importerTypes.Add(type); _importerTypes.Add(type);
@@ -90,7 +90,7 @@ public class PluginManager
{ {
using var scope = _serviceProvider.CreateScope(); using var scope = _serviceProvider.CreateScope();
var instance = (IDataProcessor)ActivatorUtilities.CreateInstance(scope.ServiceProvider, type); var instance = (IDataProcessor)ActivatorUtilities.CreateInstance(scope.ServiceProvider, type);
if (instance.CanProcess(processorType)) if (instance.CanProcess(processorType))
{ {
var scopedProvider = _serviceProvider.CreateScope().ServiceProvider; var scopedProvider = _serviceProvider.CreateScope().ServiceProvider;
@@ -113,7 +113,7 @@ public class PluginManager
{ {
using var scope = _serviceProvider.CreateScope(); using var scope = _serviceProvider.CreateScope();
var instance = (IDataImporter)ActivatorUtilities.CreateInstance(scope.ServiceProvider, type); var instance = (IDataImporter)ActivatorUtilities.CreateInstance(scope.ServiceProvider, type);
if (instance.CanImport(importerType)) if (instance.CanImport(importerType))
{ {
var scopedProvider = _serviceProvider.CreateScope().ServiceProvider; var scopedProvider = _serviceProvider.CreateScope().ServiceProvider;
@@ -132,7 +132,5 @@ public class PluginManager
{ {
return _exporters.FirstOrDefault(e => e.CanExport(exporterType)); return _exporters.FirstOrDefault(e => e.CanExport(exporterType));
} }
public int GetPluginsCount() => _processorTypes.Count + _importerTypes.Count + _exporters.Count;
public IEnumerable<IDataExporter> GetAllExporters() => _exporters.AsReadOnly();
public IEnumerable<IPlugin> GetAllPlugins() => _plugins.AsReadOnly();
} }

View File

@@ -0,0 +1,92 @@
using Microsoft.AspNetCore.Mvc.Testing;
using Xunit;
using Xunit.Abstractions;
using System.Text.Json;
namespace DiunaBI.Tests;
public class ApiConnectionTests : IClassFixture<WebApplicationFactory<Program>>
{
private readonly WebApplicationFactory<Program> _factory;
private readonly ITestOutputHelper _output;
public ApiConnectionTests(WebApplicationFactory<Program> factory, ITestOutputHelper output)
{
_factory = factory;
_output = output;
}
[Fact]
public async Task PingToApi()
{
var client = _factory.CreateClient();
_output.WriteLine($"Test started: {nameof(PingToApi)}");
var response = await client.GetAsync("/api/Tests/Ping");
var content = await response.Content.ReadAsStringAsync();
var statusCode = (int)response.StatusCode;
_output.WriteLine($"Status Code: {statusCode}");
_output.WriteLine($"Response Content: {content}");
_output.WriteLine($"Headers: {string.Join(", ", response.Headers)}");
Assert.Equal(200, statusCode);
Assert.Equal("Pong", content);
}
[Fact]
[Trait("Category", "LocalOnly")]
public async Task DatabaseConnectionTest()
{
var client = _factory.CreateClient();
_output.WriteLine($"Test started: {nameof(DatabaseConnectionTest)}");
var response = await client.GetAsync("/api/Layers?start=0&limit=1");
var content = await response.Content.ReadAsStringAsync();
var statusCode = (int)response.StatusCode;
_output.WriteLine($"Status Code: {statusCode}");
_output.WriteLine($"Response Content: {content}");
_output.WriteLine($"Content Type: {response.Content.Headers.ContentType}");
Assert.Equal(200, statusCode);
var layers = JsonSerializer.Deserialize<dynamic>(content);
Assert.NotNull(layers);
}
[Fact]
public async Task LoadPluginsTest()
{
var client = _factory.CreateClient();
_output.WriteLine($"Test started: {nameof(LoadPluginsTest)}");
var pluginsPath = Path.Combine(AppContext.BaseDirectory, "Plugins");
_output.WriteLine($"Looking for plugins in: {pluginsPath}");
if (Directory.Exists(pluginsPath))
{
_output.WriteLine("Files in plugins directory:");
foreach (var file in Directory.GetFiles(pluginsPath))
{
_output.WriteLine($"- {Path.GetFileName(file)}");
}
}
else
{
_output.WriteLine("❌ Plugins directory not found!");
}
var response = await client.GetAsync("/api/Tests/Plugins");
var content = await response.Content.ReadAsStringAsync();
_output.WriteLine($"API Response: {content}");
if (!int.TryParse(content, out var pluginsCount))
{
_output.WriteLine($"❌ Failed to parse plugins count from response: {content}");
Assert.Fail($"Expected numeric response but got: {content}");
}
Assert.Equal(200, (int)response.StatusCode);
Assert.True(pluginsCount > 0,
$"Expected plugins count to be greater than 0. Got: {pluginsCount}");
}
}

View File

@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="xunit" Version="2.6.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DiunaBI.WebAPI\DiunaBI.WebAPI.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,28 +0,0 @@
using System.Data;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Data.SqlClient;
using DiunaBI.Core.Models;
namespace DiunaBI.Core.Controllers;
[ApiController]
[Route("api/[controller]")]
public class AdminController : Controller
{
private readonly IConfiguration _configuration;
public AdminController(
IConfiguration configuration)
{
_configuration = configuration;
}
[HttpGet]
[Route("Version")]
public IActionResult GetVersion()
{
return Ok(new { version = _configuration["app-version"] });
}
}

View File

@@ -1,25 +0,0 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace DiunaBI.WebAPI.Controllers;
[ApiController]
[Route("api/[controller]")]
[Authorize]
public class PingController : Controller
{
private readonly IConfiguration _configuration;
public PingController(
IConfiguration configuration)
{
_configuration = configuration;
}
[HttpGet]
[Route("Ping")]
[AllowAnonymous]
public IActionResult Ping()
{
return Ok(_configuration["PONG"]);
}
}

View File

@@ -0,0 +1,34 @@
using DiunaBI.Core.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace DiunaBI.WebAPI.Controllers;
[ApiController]
[Route("api/[controller]")]
[Authorize]
public class TestsController : Controller
{
private readonly PluginManager _pluginManager;
public TestsController(
PluginManager pluginManager)
{
_pluginManager = pluginManager;
}
[HttpGet]
[Route("Ping")]
[AllowAnonymous]
public IActionResult Ping()
{
return Ok("Pong");
}
[HttpGet]
[Route("Plugins")]
[AllowAnonymous]
public IActionResult GetPlugins()
{
var plugins = _pluginManager.GetPluginsCount();
return Ok(plugins);
}
}

View File

@@ -159,4 +159,6 @@ app.Run();
if (app.Environment.IsProduction()) if (app.Environment.IsProduction())
{ {
Log.CloseAndFlush(); Log.CloseAndFlush();
} }
// for testing purposes
public partial class Program { }

View File

@@ -1,4 +1,4 @@

Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17 # Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59 VisualStudioVersion = 17.0.31903.59
@@ -9,6 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DiunaBI.Core", "DiunaBI.Cor
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DiunaBI.Plugins.Morska", "DiunaBI.Plugins.Morska\DiunaBI.Plugins.Morska.csproj", "{B5416A3F-550A-468D-852F-20B24243FD68}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DiunaBI.Plugins.Morska", "DiunaBI.Plugins.Morska\DiunaBI.Plugins.Morska.csproj", "{B5416A3F-550A-468D-852F-20B24243FD68}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DiunaBI.Tests", "DiunaBI.Tests\DiunaBI.Tests.csproj", "{7D99AF7E-1FC7-4EC0-A320-F1A81D396F93}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@@ -34,5 +36,9 @@ Global
{8C346BEA-A209-4E8F-A6BF-70B42D9106C8}.Debug|Any CPU.Build.0 = Debug|Any CPU {8C346BEA-A209-4E8F-A6BF-70B42D9106C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8C346BEA-A209-4E8F-A6BF-70B42D9106C8}.Release|Any CPU.ActiveCfg = Release|Any CPU {8C346BEA-A209-4E8F-A6BF-70B42D9106C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8C346BEA-A209-4E8F-A6BF-70B42D9106C8}.Release|Any CPU.Build.0 = Release|Any CPU {8C346BEA-A209-4E8F-A6BF-70B42D9106C8}.Release|Any CPU.Build.0 = Release|Any CPU
{7D99AF7E-1FC7-4EC0-A320-F1A81D396F93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7D99AF7E-1FC7-4EC0-A320-F1A81D396F93}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7D99AF7E-1FC7-4EC0-A320-F1A81D396F93}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7D99AF7E-1FC7-4EC0-A320-F1A81D396F93}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

View File

@@ -1,3 +1,3 @@
### ###
GET http://localhost:5400/api/Layers/RunQueueJobs/10763478CB738D4ecb2h76g803478CB738D4e GET http://localhost:5400/api/Tests/Plugins