From 86c906f8db6be22951fda88a82d25f123789717d Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Sat, 15 Mar 2025 21:00:00 -0500 Subject: [PATCH] Add project for automated tests Had to remove the responsibility of providing the current version of the application from UpdateService. A new IVersionProvider can be used to get the version. This also allows for this to be mocked in tests. --- LANCommander.Server.Services/BeaconService.cs | 6 +- .../IServiceCollectionExtensions.cs | 64 ++++++++++++++++ .../IVersionProvider.cs | 8 ++ .../Mappers/MappingProfile.cs | 75 +++++++++++++++++++ LANCommander.Server.Services/UpdateService.cs | 16 ++-- .../ApplicationFactory.cs | 41 ++++++++++ .../Client/AuthenticationTests.cs | 35 +++++++++ LANCommander.Server.Tests/ClientFixture.cs | 16 ++++ .../LANCommander.Server.Tests.csproj | 36 +++++++++ .../Controllers/Api/LauncherController.cs | 8 +- .../LANCommander.Server.csproj | 4 + .../Middlewares/ApiVersioningMiddleware.cs | 3 +- LANCommander.Server/Program.cs | 3 + .../Providers/VersionProvider.cs | 16 ++++ LANCommander.Server/Startup/Services.cs | 59 ++------------- .../UI/Pages/Settings/Tools/Index.razor | 3 +- .../UI/Pages/Settings/Updates.razor | 3 +- .../UI/Shared/BasicLayout.razor | 3 +- .../UI/Shared/MainLayout.razor | 6 +- LANCommander.sln | 6 ++ 20 files changed, 337 insertions(+), 74 deletions(-) create mode 100644 LANCommander.Server.Services/Extensions/IServiceCollectionExtensions.cs create mode 100644 LANCommander.Server.Services/IVersionProvider.cs create mode 100644 LANCommander.Server.Services/Mappers/MappingProfile.cs create mode 100644 LANCommander.Server.Tests/ApplicationFactory.cs create mode 100644 LANCommander.Server.Tests/Client/AuthenticationTests.cs create mode 100644 LANCommander.Server.Tests/ClientFixture.cs create mode 100644 LANCommander.Server.Tests/LANCommander.Server.Tests.csproj create mode 100644 LANCommander.Server/Providers/VersionProvider.cs diff --git a/LANCommander.Server.Services/BeaconService.cs b/LANCommander.Server.Services/BeaconService.cs index eeba70b2..308c35dc 100644 --- a/LANCommander.Server.Services/BeaconService.cs +++ b/LANCommander.Server.Services/BeaconService.cs @@ -5,7 +5,9 @@ using Microsoft.Extensions.Logging; namespace LANCommander.Server.Services { - public class BeaconService(ILogger logger) : BaseService(logger), IHostedService, IDisposable + public class BeaconService( + ILogger logger, + IVersionProvider versionProvider) : BaseService(logger), IHostedService, IDisposable { private Beacon _beacon; @@ -25,7 +27,7 @@ namespace LANCommander.Server.Services { _settings.Beacon?.Address, _settings.Beacon?.Name, - UpdateService.GetCurrentVersion().ToString(), + versionProvider.GetCurrentVersion().ToString(), }; _beacon.BeaconData = String.Join('|', dataParts); diff --git a/LANCommander.Server.Services/Extensions/IServiceCollectionExtensions.cs b/LANCommander.Server.Services/Extensions/IServiceCollectionExtensions.cs new file mode 100644 index 00000000..892de53e --- /dev/null +++ b/LANCommander.Server.Services/Extensions/IServiceCollectionExtensions.cs @@ -0,0 +1,64 @@ +using LANCommander.SDK; +using LANCommander.Server.Services.Factories; +using LANCommander.Server.Services.Importers; +using LANCommander.Server.Services.MediaGrabbers; +using LANCommander.Server.Services.Models; +using Microsoft.Extensions.DependencyInjection; + +namespace LANCommander.Server.Services.Extensions; + +public static class IServiceCollectionExtensions +{ + public static IServiceCollection AddLANCommanderServer(this IServiceCollection services, Settings settings) + { + services.AddSingleton(new Client("", "")); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddTransient(); + services.AddScoped(typeof(ImportService<>)); + + // Register importers + services.AddScoped, GameImporter>(); + services.AddScoped, ServerImporter>(); + services.AddScoped, RedistributableImporter>(); + + services.AddSingleton(); + services.AddSingleton(); + + services.AddAutoMapper(typeof(MappingProfile)); + services.AddFusionCache(); + + if (settings.Beacon.Enabled) + services.AddHostedService(); + + return services; + } +} \ No newline at end of file diff --git a/LANCommander.Server.Services/IVersionProvider.cs b/LANCommander.Server.Services/IVersionProvider.cs new file mode 100644 index 00000000..56ea399e --- /dev/null +++ b/LANCommander.Server.Services/IVersionProvider.cs @@ -0,0 +1,8 @@ +using Semver; + +namespace LANCommander.Server.Services; + +public interface IVersionProvider +{ + SemVersion GetCurrentVersion(); +} \ No newline at end of file diff --git a/LANCommander.Server.Services/Mappers/MappingProfile.cs b/LANCommander.Server.Services/Mappers/MappingProfile.cs new file mode 100644 index 00000000..ece31241 --- /dev/null +++ b/LANCommander.Server.Services/Mappers/MappingProfile.cs @@ -0,0 +1,75 @@ +using System.Linq.Expressions; +using AutoMapper; +using LANCommander.SDK.Models; + +namespace LANCommander.Server +{ + public class MappingProfile : Profile + { + public MappingProfile() + { + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + + CreateEntityReferenceMap(g => g.Title); + + CreateMap() + .ForMember(dest => + dest.IPXRelayHost, + opt => opt.MapFrom(src => src.IPXRelay.Host)) + .ForMember(dest => + dest.IPXRelayPort, + opt => opt.MapFrom(src => src.IPXRelay.Port)) + .ForMember(dest => + dest.EnableUserLibraries, + opt => opt.MapFrom(src => src.Library.EnableUserLibraries)); + + CreateMap() + .ForMember(dest => + dest.IsPrimaryAction, + opt => opt.MapFrom(src => src.PrimaryAction)); + + CreateMap() + .MaxDepth(5) + .ForMember(dest => + dest.DependentGames, + opt => opt.MapFrom(src => src.DependentGames.Select(d => d.Id))); + + CreateMap() + .ForMember(dest => + dest.Cover, + opt => opt.MapFrom(src => src.Media.Where(m => m.Type == SDK.Enums.MediaType.Cover).FirstOrDefault())); + + CreateMap(); + + CreateMap() + .ForMember(dest => dest.Name, + opt => opt.MapFrom(src => src.Title)); + } + + private void CreateEntityReferenceMap(Expression> nameMember) + { + CreateMap() + .ForMember(dest => dest.Name, opt => opt.MapFrom(nameMember)); + } + } +} diff --git a/LANCommander.Server.Services/UpdateService.cs b/LANCommander.Server.Services/UpdateService.cs index d311be78..4ab6d519 100644 --- a/LANCommander.Server.Services/UpdateService.cs +++ b/LANCommander.Server.Services/UpdateService.cs @@ -16,6 +16,7 @@ namespace LANCommander.Server.Services public sealed class UpdateService( ILogger logger, IHostApplicationLifetime applicationLifetime, + IVersionProvider versionProvider, ServerService serverService, ServerProcessService serverProcessService) : BaseService(logger) { @@ -30,13 +31,6 @@ namespace LANCommander.Server.Services _gitHub = new GitHubClient(new ProductHeaderValue(_repository)); } - public static SemVersion GetCurrentVersion() - { - var productVersion = FileVersionInfo.GetVersionInfo(Assembly.GetEntryAssembly().Location).ProductVersion; - - return SemVersion.Parse(productVersion); - } - public async Task> GetLauncherArtifactsAsync() { if (!_settings.Launcher.HostUpdates) @@ -47,7 +41,7 @@ namespace LANCommander.Server.Services public IEnumerable GetLauncherArtifactsFromLocalFiles() { - var currentVersion = GetCurrentVersion(); + var currentVersion = versionProvider.GetCurrentVersion(); var downloadedLaunchers = Directory.GetFiles(_settings.Launcher.StoragePath, $"LANCommander.Launcher.*v{currentVersion.WithoutMetadata()}.zip"); foreach (var downloadedLauncher in downloadedLaunchers) @@ -56,7 +50,7 @@ namespace LANCommander.Server.Services public async IAsyncEnumerable GetLauncherArtifactsFromGitHubAsync() { - var currentVersion = GetCurrentVersion(); + var currentVersion = versionProvider.GetCurrentVersion(); if (!String.IsNullOrWhiteSpace(_settings.Launcher.VersionOverride)) currentVersion = SemVersion.Parse(_settings.Launcher.VersionOverride, SemVersionStyles.AllowV); @@ -183,14 +177,14 @@ namespace LANCommander.Server.Services if (SemVersion.TryParse(version, SemVersionStyles.AllowV, out SemVersion semVersion)) return semVersion; else - return GetCurrentVersion(); + return versionProvider.GetCurrentVersion(); } public async Task UpdateAvailableAsync() { var latestVersion = await GetLatestVersionAsync(); - var sortOrder = GetCurrentVersion().ComparePrecedenceTo(latestVersion); + var sortOrder = versionProvider.GetCurrentVersion().ComparePrecedenceTo(latestVersion); return sortOrder < 0; } diff --git a/LANCommander.Server.Tests/ApplicationFactory.cs b/LANCommander.Server.Tests/ApplicationFactory.cs new file mode 100644 index 00000000..95287cca --- /dev/null +++ b/LANCommander.Server.Tests/ApplicationFactory.cs @@ -0,0 +1,41 @@ +using System.Data.Common; +using LANCommander.Server.Data; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc.Testing; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.Extensions.DependencyInjection; + +namespace LANCommander.Server.Tests; + +public class ApplicationFactory + : WebApplicationFactory where TProgram : class +{ + protected override void ConfigureWebHost(IWebHostBuilder builder) + { + builder.ConfigureServices(services => + { + var dbContextDescriptor = services.SingleOrDefault( + d => d.ServiceType == + typeof(IDbContextOptionsConfiguration)); + + services.Remove(dbContextDescriptor); + + var dbConnectionDescriptor = services.SingleOrDefault( + d => d.ServiceType == + typeof(DbConnection)); + + services.Remove(dbConnectionDescriptor); + + services.AddDbContextFactory(optionsBuilder => + { + optionsBuilder.UseInMemoryDatabase("Test"); + }); + + services.AddDbContext(optionsBuilder => + { + optionsBuilder.UseInMemoryDatabase("Test"); + }); + }); + } +} \ No newline at end of file diff --git a/LANCommander.Server.Tests/Client/AuthenticationTests.cs b/LANCommander.Server.Tests/Client/AuthenticationTests.cs new file mode 100644 index 00000000..ed33cdb6 --- /dev/null +++ b/LANCommander.Server.Tests/Client/AuthenticationTests.cs @@ -0,0 +1,35 @@ +using Microsoft.AspNetCore.Mvc.Testing; +using Shouldly; + +namespace LANCommander.Server.Tests.Client; + +public class AuthenticationTests : + IClassFixture>, + IClassFixture +{ + private readonly WebApplicationFactory _factory; + private readonly SDK.Client _client; + + public AuthenticationTests( + WebApplicationFactory factory, + ClientFixture clientFixture) + { + _factory = factory; + _client = clientFixture.Client; + } + + [Theory] + [InlineData("http://localhost:1337")] // Good users + [InlineData("https://localhost:1337")] // Uninformed users + [InlineData("localhost")] // Lazy users + [InlineData("localhost:1337")] // Forgivable users + [InlineData("localhost:1338")] // PEBKAC users + public async Task CanReachServer(string serverAddress) + { + var app = _factory.CreateClient(); + + await _client.ChangeServerAddressAsync(serverAddress); + + _client.GetServerAddress().ShouldBe("http://localhost:1337"); + } +} \ No newline at end of file diff --git a/LANCommander.Server.Tests/ClientFixture.cs b/LANCommander.Server.Tests/ClientFixture.cs new file mode 100644 index 00000000..83368998 --- /dev/null +++ b/LANCommander.Server.Tests/ClientFixture.cs @@ -0,0 +1,16 @@ +namespace LANCommander.Server.Tests; + +public class ClientFixture : IDisposable +{ + public SDK.Client Client { get; set; } + + public ClientFixture() + { + Client = new SDK.Client("", "C:\\Games"); + } + + public void Dispose() + { + Client.Disconnect(); + } +} \ No newline at end of file diff --git a/LANCommander.Server.Tests/LANCommander.Server.Tests.csproj b/LANCommander.Server.Tests/LANCommander.Server.Tests.csproj new file mode 100644 index 00000000..2cc2df4d --- /dev/null +++ b/LANCommander.Server.Tests/LANCommander.Server.Tests.csproj @@ -0,0 +1,36 @@ + + + + net9.0 + enable + enable + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LANCommander.Server/Controllers/Api/LauncherController.cs b/LANCommander.Server/Controllers/Api/LauncherController.cs index 9dd4b821..eee31b53 100644 --- a/LANCommander.Server/Controllers/Api/LauncherController.cs +++ b/LANCommander.Server/Controllers/Api/LauncherController.cs @@ -1,4 +1,5 @@ using LANCommander.SDK.Models; +using LANCommander.Server.Providers; using LANCommander.Server.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -11,12 +12,15 @@ namespace LANCommander.Server.Controllers.Api [ApiController] public class LauncherController : BaseApiController { + private readonly IVersionProvider _versionProvider; private readonly UpdateService UpdateService; public LauncherController( ILogger logger, + IVersionProvider versionProvider, UpdateService updateService) : base(logger) { + _versionProvider = versionProvider; UpdateService = updateService; } @@ -24,7 +28,7 @@ namespace LANCommander.Server.Controllers.Api [HttpGet("Download")] public async Task DownloadAsync() { - var version = UpdateService.GetCurrentVersion(); + var version = _versionProvider.GetCurrentVersion(); var settings = SettingService.GetSettings(); var fileName = $"LANCommander.Launcher-Windows-x64-v{version}.zip"; var path = Path.Combine(settings.Launcher.StoragePath, fileName); @@ -55,7 +59,7 @@ namespace LANCommander.Server.Controllers.Api if (SemVersion.TryParse(launcherVersionString, SemVersionStyles.Any, out var launcherVersion)) { - var currentVersion = UpdateService.GetCurrentVersion(); + var currentVersion = _versionProvider.GetCurrentVersion(); if (launcherVersion.ComparePrecedenceTo(currentVersion) < 0) { diff --git a/LANCommander.Server/LANCommander.Server.csproj b/LANCommander.Server/LANCommander.Server.csproj index 16d03776..93ff4bac 100644 --- a/LANCommander.Server/LANCommander.Server.csproj +++ b/LANCommander.Server/LANCommander.Server.csproj @@ -55,6 +55,10 @@ + + + + diff --git a/LANCommander.Server/Middlewares/ApiVersioningMiddleware.cs b/LANCommander.Server/Middlewares/ApiVersioningMiddleware.cs index 1375a01a..242c50df 100644 --- a/LANCommander.Server/Middlewares/ApiVersioningMiddleware.cs +++ b/LANCommander.Server/Middlewares/ApiVersioningMiddleware.cs @@ -6,9 +6,10 @@ namespace LANCommander.Server { public async Task InvokeAsync(HttpContext context) { + var versionProvider = context.RequestServices.GetService(); var headers = context.Response.Headers; - headers.Append("X-API-Version", UpdateService.GetCurrentVersion().ToString()); + headers.Append("X-API-Version", versionProvider?.GetCurrentVersion().ToString()); await next(context); } diff --git a/LANCommander.Server/Program.cs b/LANCommander.Server/Program.cs index 94d23b6f..85a854e6 100644 --- a/LANCommander.Server/Program.cs +++ b/LANCommander.Server/Program.cs @@ -86,3 +86,6 @@ app.GenerateThumbnails(); app.Run(); +public partial class Program +{ +} \ No newline at end of file diff --git a/LANCommander.Server/Providers/VersionProvider.cs b/LANCommander.Server/Providers/VersionProvider.cs new file mode 100644 index 00000000..ce3e31c1 --- /dev/null +++ b/LANCommander.Server/Providers/VersionProvider.cs @@ -0,0 +1,16 @@ +using System.Diagnostics; +using System.Reflection; +using LANCommander.Server.Services; +using Semver; + +namespace LANCommander.Server.Providers; + +public class VersionProvider : IVersionProvider +{ + public SemVersion GetCurrentVersion() + { + var version = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).ProductVersion; + + return SemVersion.Parse(version); + } +} \ No newline at end of file diff --git a/LANCommander.Server/Startup/Services.cs b/LANCommander.Server/Startup/Services.cs index 5a222960..0ec82ec8 100644 --- a/LANCommander.Server/Startup/Services.cs +++ b/LANCommander.Server/Startup/Services.cs @@ -1,8 +1,6 @@ -using LANCommander.SDK; +using LANCommander.Server.Providers; using LANCommander.Server.Services; -using LANCommander.Server.Services.Factories; -using LANCommander.Server.Services.Importers; -using LANCommander.Server.Services.MediaGrabbers; +using LANCommander.Server.Services.Extensions; using LANCommander.Server.Services.Models; using Serilog; @@ -13,60 +11,15 @@ public static class Services public static WebApplicationBuilder AddLANCommanderServices(this WebApplicationBuilder builder, Settings settings) { Log.Debug("Registering services"); - builder.Services.AddSingleton(new Client("", "")); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddTransient(); - builder.Services.AddScoped(typeof(ImportService<>)); - - // Register importers - builder.Services.AddScoped, GameImporter>(); - builder.Services.AddScoped, ServerImporter>(); - builder.Services.AddScoped, RedistributableImporter>(); - - builder.Services.AddSingleton(); - builder.Services.AddSingleton(); - builder.Services.AddAutoMapper(typeof(LANCommanderMappingProfile)); - builder.Services.AddFusionCache(); + builder.Services.AddLANCommanderServer(settings); + + builder.Services.AddSingleton(); + builder.Services.AddAntDesign(); builder.Services.AddHttpClient(); builder.Services.AddHttpContextAccessor(); - if (settings.Beacon.Enabled) - { - Log.Debug("The beacons have been lit! LANCommander calls for players!"); - builder.Services.AddHostedService(); - } - return builder; } } \ No newline at end of file diff --git a/LANCommander.Server/UI/Pages/Settings/Tools/Index.razor b/LANCommander.Server/UI/Pages/Settings/Tools/Index.razor index 6d454472..5b2e0710 100644 --- a/LANCommander.Server/UI/Pages/Settings/Tools/Index.razor +++ b/LANCommander.Server/UI/Pages/Settings/Tools/Index.razor @@ -7,6 +7,7 @@ @inject PageService PageService @inject UpdateService UpdateService @inject StorageLocationService StorageLocationService +@inject IVersionProvider VersionProvider @inject IMessageService MessageService @inject IFusionCache FusionCache @inject ILogger Logger @@ -125,7 +126,7 @@ await Task.Yield(); await InvokeAsync(StateHasChanged); - var currentVersion = UpdateService.GetCurrentVersion(); + var currentVersion = VersionProvider.GetCurrentVersion(); var currentRelease = await UpdateService.GetReleaseAsync(currentVersion); if (currentRelease != null) diff --git a/LANCommander.Server/UI/Pages/Settings/Updates.razor b/LANCommander.Server/UI/Pages/Settings/Updates.razor index 35e40ce3..fea29570 100644 --- a/LANCommander.Server/UI/Pages/Settings/Updates.razor +++ b/LANCommander.Server/UI/Pages/Settings/Updates.razor @@ -4,6 +4,7 @@ @using Semver @inject IMessageService MessageService @inject UpdateService UpdateService +@inject IVersionProvider VersionProvider @inject ILogger Logger @attribute [Authorize(Roles = RoleService.AdministratorRoleName)] @@ -93,7 +94,7 @@ await InvokeAsync(StateHasChanged); await Task.Yield(); - CurrentVersion = UpdateService.GetCurrentVersion(); + CurrentVersion = VersionProvider.GetCurrentVersion(); UpdateAvailable = await UpdateService.UpdateAvailableAsync(); LatestVersion = await UpdateService.GetLatestVersionAsync(); Releases = await UpdateService.GetReleasesAsync(5); diff --git a/LANCommander.Server/UI/Shared/BasicLayout.razor b/LANCommander.Server/UI/Shared/BasicLayout.razor index b1ad681f..ed8802a6 100644 --- a/LANCommander.Server/UI/Shared/BasicLayout.razor +++ b/LANCommander.Server/UI/Shared/BasicLayout.razor @@ -1,4 +1,5 @@ @inherits LayoutComponentBase +@inject IVersionProvider VersionProvider @@ -6,6 +7,6 @@
- LANCommander v@(UpdateService.GetCurrentVersion().ToString()) + LANCommander v@(VersionProvider.GetCurrentVersion().ToString())
\ No newline at end of file diff --git a/LANCommander.Server/UI/Shared/MainLayout.razor b/LANCommander.Server/UI/Shared/MainLayout.razor index 1800ca4f..20418aa7 100644 --- a/LANCommander.Server/UI/Shared/MainLayout.razor +++ b/LANCommander.Server/UI/Shared/MainLayout.razor @@ -1,4 +1,6 @@ -@inherits LayoutComponentBase +@using LANCommander.Server.Providers +@inherits LayoutComponentBase +@inject IVersionProvider VersionProvider @inject NavigationManager NavigationManager @@ -17,7 +19,7 @@ \ No newline at end of file diff --git a/LANCommander.sln b/LANCommander.sln index bf6a65b7..d167f1d2 100644 --- a/LANCommander.sln +++ b/LANCommander.sln @@ -40,6 +40,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LANCommander.Server.Data.My EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LANCommander.Server.Data.PostgreSQL", "LANCommander.Server.Data.PostgreSQL\LANCommander.Server.Data.PostgreSQL.csproj", "{225A5DA1-9719-4EAA-A27E-C6C65D7324D1}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LANCommander.Server.Tests", "LANCommander.Server.Tests\LANCommander.Server.Tests.csproj", "{C6B4CEDF-761B-48FC-B6FE-5A66EF2412BE}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -110,6 +112,10 @@ Global {225A5DA1-9719-4EAA-A27E-C6C65D7324D1}.Debug|Any CPU.Build.0 = Debug|Any CPU {225A5DA1-9719-4EAA-A27E-C6C65D7324D1}.Release|Any CPU.ActiveCfg = Release|Any CPU {225A5DA1-9719-4EAA-A27E-C6C65D7324D1}.Release|Any CPU.Build.0 = Release|Any CPU + {C6B4CEDF-761B-48FC-B6FE-5A66EF2412BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C6B4CEDF-761B-48FC-B6FE-5A66EF2412BE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C6B4CEDF-761B-48FC-B6FE-5A66EF2412BE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C6B4CEDF-761B-48FC-B6FE-5A66EF2412BE}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE