diff --git a/src/backend/.dockerignore b/src/backend/.dockerignore index 3729ff0c..fe1152bd 100644 --- a/src/backend/.dockerignore +++ b/src/backend/.dockerignore @@ -22,4 +22,9 @@ **/secrets.dev.yaml **/values.dev.yaml LICENSE -README.md \ No newline at end of file +README.md +!**/.gitignore +!.git/HEAD +!.git/config +!.git/packed-refs +!.git/refs/heads/** \ No newline at end of file diff --git a/src/backend/Backend.sln b/src/backend/Backend.sln index a887cd7c..07b65474 100644 --- a/src/backend/Backend.sln +++ b/src/backend/Backend.sln @@ -5,7 +5,7 @@ VisualStudioVersion = 17.7.34031.279 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebApi", "WebApi\WebApi.csproj", "{967AAD03-89D9-4352-BAF5-40CF10F28C35}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebApi.Tests", "..\..\tests\backend\WebApi.Tests\WebApi.Tests.csproj", "{83C523DE-4F91-4C54-A4F0-5D24CCF251D0}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebApi.Tests", "..\..\tests\backend\WebApi.Tests\WebApi.Tests.csproj", "{83C523DE-4F91-4C54-A4F0-5D24CCF251D0}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9EBA80A2-4F3D-4EBC-AC53-3D4DE1719443}" ProjectSection(SolutionItems) = preProject @@ -23,6 +23,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{F9FCA971-68B global.json = global.json EndProjectSection EndProject +Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{69BC9238-50AC-4F4C-B884-717F1E75493F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -37,6 +39,10 @@ Global {83C523DE-4F91-4C54-A4F0-5D24CCF251D0}.Debug|Any CPU.Build.0 = Debug|Any CPU {83C523DE-4F91-4C54-A4F0-5D24CCF251D0}.Release|Any CPU.ActiveCfg = Release|Any CPU {83C523DE-4F91-4C54-A4F0-5D24CCF251D0}.Release|Any CPU.Build.0 = Release|Any CPU + {69BC9238-50AC-4F4C-B884-717F1E75493F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {69BC9238-50AC-4F4C-B884-717F1E75493F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {69BC9238-50AC-4F4C-B884-717F1E75493F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {69BC9238-50AC-4F4C-B884-717F1E75493F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/backend/WebApi/Controllers/WeatherForecastController.cs b/src/backend/WebApi/Controllers/WeatherForecastController.cs index 5f75962d..c13fe110 100644 --- a/src/backend/WebApi/Controllers/WeatherForecastController.cs +++ b/src/backend/WebApi/Controllers/WeatherForecastController.cs @@ -20,17 +20,17 @@ public class WeatherForecastController(ILogger logger /// /// [HttpGet(Name = "GetWeatherForecast")] - public IEnumerable Get() + public Task>> Get() { logger.LogInformation("GetWeatherForecast was called"); - return Enumerable.Range(1, 5) - .Select(static index => new WeatherForecast - { - Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), - TemperatureC = Random.Shared.Next(-20, 55), - Summary = Summaries[Random.Shared.Next(Summaries.Length)] - }) - .ToArray(); + return Task.FromResult>>(Ok(Enumerable.Range(1, 5) + .Select(static index => new WeatherForecast + { + Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), + TemperatureC = Random.Shared.Next(-20, 55), + Summary = Summaries[Random.Shared.Next(Summaries.Length)] + }) + .ToArray())); } } \ No newline at end of file diff --git a/src/backend/WebApi/Dockerfile b/src/backend/WebApi/Dockerfile index 2fff58a2..365b44cf 100644 --- a/src/backend/WebApi/Dockerfile +++ b/src/backend/WebApi/Dockerfile @@ -11,11 +11,12 @@ WORKDIR /src COPY ["WebApi/WebApi.csproj", "WebApi/"] #COPY ["Common/Common.csproj", "Common/"] COPY ["Directory.Build.props", "./"] -COPY [".git/", "./.git/"] +# COPY [".git/", "./.git/"] RUN dotnet restore "WebApi/WebApi.csproj" COPY . . WORKDIR "/src/WebApi" RUN dotnet build "WebApi.csproj" -c Release -o /app/build +RUN dotnet dev-certs https FROM build AS publish RUN dotnet publish "WebApi.csproj" -c Release -o /app/publish /p:UseAppHost=false @@ -23,4 +24,5 @@ RUN dotnet publish "WebApi.csproj" -c Release -o /app/publish /p:UseAppHost=fals FROM base AS final WORKDIR /app COPY --from=publish /app/publish . +COPY --from=build /root/.dotnet/corefx/cryptography/x509stores/my/* /root/.dotnet/corefx/cryptography/x509stores/my/ ENTRYPOINT ["dotnet", "WebApi.dll"] \ No newline at end of file diff --git a/src/backend/WebApi/WebApi.csproj b/src/backend/WebApi/WebApi.csproj index ffb15a34..ac06d0b8 100644 --- a/src/backend/WebApi/WebApi.csproj +++ b/src/backend/WebApi/WebApi.csproj @@ -5,6 +5,7 @@ Linux api True + ..\docker-compose.dcproj diff --git a/src/backend/docker-compose.dcproj b/src/backend/docker-compose.dcproj new file mode 100644 index 00000000..e1a33f6b --- /dev/null +++ b/src/backend/docker-compose.dcproj @@ -0,0 +1,19 @@ + + + + 2.1 + Linux + False + 69bc9238-50ac-4f4c-b884-717f1e75493f + LaunchBrowser + {Scheme}://localhost:{ServicePort}/swagger + webapi + + + + docker-compose.yml + + + + + \ No newline at end of file diff --git a/src/backend/docker-compose.override.yml b/src/backend/docker-compose.override.yml new file mode 100644 index 00000000..4f841199 --- /dev/null +++ b/src/backend/docker-compose.override.yml @@ -0,0 +1,14 @@ +version: '3.4' + +services: + webapi: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - ASPNETCORE_HTTP_PORTS=8080 + - ASPNETCORE_HTTPS_PORTS=8081 + ports: + - "8080" + - "8081" + volumes: + - ${APPDATA}/Microsoft/UserSecrets:/home/app/.microsoft/usersecrets:ro + - ${APPDATA}/ASP.NET/Https:/home/app/.aspnet/https:ro \ No newline at end of file diff --git a/src/backend/docker-compose.yml b/src/backend/docker-compose.yml new file mode 100644 index 00000000..3d3beed5 --- /dev/null +++ b/src/backend/docker-compose.yml @@ -0,0 +1,8 @@ +version: '3.4' + +services: + webapi: + image: ${DOCKER_REGISTRY-}webapi + build: + context: . + dockerfile: WebApi/Dockerfile diff --git a/src/backend/launchSettings.json b/src/backend/launchSettings.json new file mode 100644 index 00000000..8ce4ee14 --- /dev/null +++ b/src/backend/launchSettings.json @@ -0,0 +1,11 @@ +{ + "profiles": { + "Docker Compose": { + "commandName": "DockerCompose", + "commandVersion": "1.0", + "serviceActions": { + "webapi": "StartDebugging" + } + } + } +} \ No newline at end of file diff --git a/tests/backend/WebApi.Tests/Controllers/WeatherForecastControllerTests.cs b/tests/backend/WebApi.Tests/Controllers/WeatherForecastControllerTests.cs new file mode 100644 index 00000000..4dff53dc --- /dev/null +++ b/tests/backend/WebApi.Tests/Controllers/WeatherForecastControllerTests.cs @@ -0,0 +1,119 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using Moq; +using WebApi.Controllers; +using WebApi.Entities; + +namespace WebApi.Tests.Controllers; + +[TestFixture] +public class WeatherForecastControllerTests +{ + [SetUp] + public void SetUp() + { + _loggerMock = new Mock>(); + _controller = new WeatherForecastController(_loggerMock.Object); + } + private Mock> _loggerMock; + private WeatherForecastController _controller; + + [Test] + public async Task Get_ReturnsOkResult() + { + // Act + var result = await _controller.Get(); + + // Assert + Assert.IsInstanceOf>>(result); + Assert.IsInstanceOf(result.Result); + } + + [Test] + public async Task Get_ReturnsFiveWeatherForecasts() + { + // Act + var result = await _controller.Get(); + + // Assert + Assert.NotNull(result.Result); + Assert.IsAssignableFrom(result.Result); + var okResult = (OkObjectResult) result.Result; + Assert.NotNull(okResult.Value); + Assert.IsAssignableFrom(okResult.Value); + Assert.That(((WeatherForecast[]) okResult.Value).Count(), Is.EqualTo(5)); + } + + [Test] + public async Task Get_ReturnsWeatherForecastsWithCorrectProperties() + { + // Act + var result = await _controller.Get(); + + // Assert + Assert.NotNull(result.Result); + Assert.IsAssignableFrom(result.Result); + var okResult = (OkObjectResult) result.Result; + Assert.NotNull(okResult.Value); + Assert.IsAssignableFrom(okResult.Value); + foreach (var weatherForecast in (WeatherForecast[]) okResult.Value) + { + Assert.IsInstanceOf(weatherForecast.Date); + Assert.IsInstanceOf(weatherForecast.TemperatureC); + Assert.IsInstanceOf(weatherForecast.Summary); + } + } + + [Test] + public async Task Get_LogsInformationMessage() + { + // Act + await _controller.Get(); + + // Assert + _loggerMock.Verify(static x => x.LogInformation(It.IsAny()), Times.Once); + } +} + +/*using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using Moq; +using WebApi.Controllers; +using WebApi.Entities; + +namespace WebApi.Tests.Controllers; + +public class WeatherForecastControllerTests +{ +private ILogger _logger; +private WeatherForecastController _controller; + +[SetUp] +public void Setup() +{ + _logger = Mock.Of>(); + _controller = new WeatherForecastController(_logger); +} + +[Test] +public async Task Get_ReturnsExpectedWeatherForecast() +{ + // Act + var result = await _controller.Get(); + + // Assert + Assert.IsInstanceOf>>(result); + Assert.IsInstanceOf>(result.Value); + Assert.IsNotNull(result.Value); + Assert.That(((IEnumerable) result.Value).Count(), Is.EqualTo(5)); + + foreach (var weatherForecast in result.Value) + { + Assert.IsInstanceOf(weatherForecast.Date); + Assert.IsInstanceOf(weatherForecast.TemperatureC); + Assert.IsInstanceOf(weatherForecast.Summary); + } + + //Mock.Get(_logger).Verify(static x => x.Log<>(It.IsAny(), It.IsAny(), default, default), Times.Once()); +} +}*/ \ No newline at end of file diff --git a/tests/backend/WebApi.Tests/WebApi.Tests.csproj b/tests/backend/WebApi.Tests/WebApi.Tests.csproj index 0c3577b4..38043856 100644 --- a/tests/backend/WebApi.Tests/WebApi.Tests.csproj +++ b/tests/backend/WebApi.Tests/WebApi.Tests.csproj @@ -1,24 +1,25 @@ - - false - true - + + false + true + - - - - - - - + + + + + + + + - - - + + + - - - + + + diff --git a/tests/backend/WebApi.Tests/packages.lock.json b/tests/backend/WebApi.Tests/packages.lock.json index 21906507..8619d564 100644 --- a/tests/backend/WebApi.Tests/packages.lock.json +++ b/tests/backend/WebApi.Tests/packages.lock.json @@ -18,6 +18,15 @@ "Microsoft.TestPlatform.TestHost": "17.8.0" } }, + "Moq": { + "type": "Direct", + "requested": "[4.20.70, )", + "resolved": "4.20.70", + "contentHash": "4rNnAwdpXJBuxqrOCzCyICXHSImOTRktCgCWXWykuF1qwoIsVvEnR7PjbMk/eLOxWvhmj5Kwt+kDV3RGUYcNwg==", + "dependencies": { + "Castle.Core": "5.1.1" + } + }, "NUnit": { "type": "Direct", "requested": "[3.14.0, )", @@ -39,6 +48,14 @@ "resolved": "4.5.0", "contentHash": "s8JpqTe9bI2f49Pfr3dFRfoVSuFQyraTj68c3XXjIS/MRGvvkLnrg6RLqnTjdShX+AdFUCCU/4Xex58AdUfs6A==" }, + "Castle.Core": { + "type": "Transitive", + "resolved": "5.1.1", + "contentHash": "rpYtIczkzGpf+EkZgDr9CClTdemhsrwA/W5hMoPjLkRFnXzH44zDLoovXeKtmxb1ykXK9aJVODSpiJml8CTw2g==", + "dependencies": { + "System.Diagnostics.EventLog": "6.0.0" + } + }, "Microsoft.AspNetCore.OpenApi": { "type": "Transitive", "resolved": "8.0.4", @@ -145,6 +162,11 @@ "resolved": "6.5.0", "contentHash": "OvbvxX+wL8skxTBttcBsVxdh73Fag4xwqEU2edh4JMn7Ws/xJHnY/JB1e9RoCb6XpDxUF3hD9A0Z1lEUx40Pfw==" }, + "System.Diagnostics.EventLog": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "lcyUiXTsETK2ALsZrX+nWuHSIQeazhqPphLfaRxzdGaG93+0kELqpgEHtwWOlQe7+jSFnKwaCAgL4kjeZCQJnw==" + }, "System.Reflection.Metadata": { "type": "Transitive", "resolved": "1.6.0", @@ -160,7 +182,19 @@ } } }, - "net8.0/linux-musl-x64": {}, - "net8.0/win-x64": {} + "net8.0/linux-musl-x64": { + "System.Diagnostics.EventLog": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "lcyUiXTsETK2ALsZrX+nWuHSIQeazhqPphLfaRxzdGaG93+0kELqpgEHtwWOlQe7+jSFnKwaCAgL4kjeZCQJnw==" + } + }, + "net8.0/win-x64": { + "System.Diagnostics.EventLog": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "lcyUiXTsETK2ALsZrX+nWuHSIQeazhqPphLfaRxzdGaG93+0kELqpgEHtwWOlQe7+jSFnKwaCAgL4kjeZCQJnw==" + } + } } } \ No newline at end of file