diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 000000000..2e626e4ea --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,132 @@ +name: Build + +on: + pull_request: + branches: [ main ] + +jobs: + + build: + + name: Test & Coverage + + runs-on: ubuntu-latest + + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + DOTNET_ROLL_FORWARD: Major + + steps: + + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Install msquic + run: | + sudo apt-get update + sudo apt-get install -y libmsquic + + - name: Download .NET SDK + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 9.0 + + - name: Restore tools + run: dotnet tool restore + + - name: Begin scan + if: env.SONAR_TOKEN != null && env.SONAR_TOKEN != '' + run: dotnet sonarscanner begin /k:"GenHTTP" /d:sonar.token="$SONAR_TOKEN" /d:sonar.cs.opencover.reportsPaths="**/coverage.opencover.xml" /d:sonar.exclusions="**/bin/**/*,**/obj/**/*,**/Playground/**/*,**/*.css,**/*.js,**/*.html" /o:"kaliumhexacyanoferrat" /k:"GenHTTP" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.branch.name="${GITHUB_REF##*/}" /d:sonar.dotnet.excludeTestProjects=true + + - name: Build project + run: dotnet build GenHTTP.slnx -c Release + + - name: Test project + run: dotnet test GenHTTP.slnx --no-build --collect:"XPlat Code Coverage" -c Release -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=opencover + + - name: End scan + if: env.SONAR_TOKEN != null && env.SONAR_TOKEN != '' + run: dotnet sonarscanner end /d:sonar.token="$SONAR_TOKEN" + + verify: + + name: ${{ matrix.os.name }} ${{ matrix.arch }} + + needs: build + + runs-on: ${{ matrix.os.runs-on }} + + env: + TEST_ENGINE: Internal + + strategy: + fail-fast: false + matrix: + include: + + - os: + name: 🐧 + runs-on: ubuntu-latest + arch: x64 + runtime: linux-x64 + platform: linux/amd64 + + - os: + name: 🐧 + runs-on: linux-arm32 + arch: arm32 + runtime: linux-arm + platform: linux/arm/v7 + + - os: + name: 🐧 + runs-on: ubuntu-22.04-arm + arch: arm64 + runtime: linux-arm64 + platform: linux/arm64/v8 + + - os: + name: 🪟 + runs-on: windows-latest + arch: x64 + runtime: win-x64 + platform: windows/amd64 + + - os: + name: 🪟 + runs-on: windows-latest + arch: arm64 + runtime: win-arm64 + platform: windows/arm64 + + - os: + name: 🍎 + runs-on: macos-15-intel + arch: x64 + runtime: osx-x64 + platform: macos/amd64 + + - os: + name: 🍎 + runs-on: macos-15 + arch: arm64 + runtime: osx-arm64 + platform: macos/arm64 + + steps: + - name: Checkout source + uses: actions/checkout@v4 + + - name: Setup .NET SDK + uses: actions/setup-dotnet@v4 + if: matrix.os.runs-on != 'linux-arm32' + with: + dotnet-version: | + 8.0 + 9.0 + + - name: Build & Test (${{ matrix.runtime }}) + run: dotnet test Testing/Acceptance/GenHTTP.Testing.Acceptance.csproj -c Release diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 0c8999357..000000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: CI - -on: - push: - pull_request: - types: [opened] - -jobs: - build: - - runs-on: ubuntu-latest - - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - DOTNET_ROLL_FORWARD: Major - - steps: - - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Install msquic - run: | - sudo apt-get update - sudo apt-get install -y libmsquic - - - name: Download .NET SDK - uses: actions/setup-dotnet@v4.1.0 - with: - dotnet-version: 9.0 - - - name: Restore tools - run: dotnet tool restore - - - name: Begin scan - if: env.SONAR_TOKEN != null && env.SONAR_TOKEN != '' - run: dotnet sonarscanner begin /k:"GenHTTP" /d:sonar.token="$SONAR_TOKEN" /d:sonar.cs.opencover.reportsPaths="**/coverage.opencover.xml" /d:sonar.exclusions="**/bin/**/*,**/obj/**/*,**/Playground/**/*,**/*.css,**/*.js,**/*.html" /o:"kaliumhexacyanoferrat" /k:"GenHTTP" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.branch.name="${GITHUB_REF##*/}" /d:sonar.dotnet.excludeTestProjects=true - - - name: Build project - run: dotnet build GenHTTP.slnx -c Release - - - name: Test project - run: dotnet test GenHTTP.slnx --no-build --collect:"XPlat Code Coverage" -c Release -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=opencover - - - name: End scan - if: env.SONAR_TOKEN != null && env.SONAR_TOKEN != '' - run: dotnet sonarscanner end /d:sonar.token="$SONAR_TOKEN" diff --git a/README.md b/README.md index 862ac07ad..78243452b 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ GenHTTP is a lightweight web server written in pure C# with a strong focus on de purpose of this project is to quickly create web services written in .NET 8 / 9, allowing developers to concentrate on the functionality rather than on messing around with configuration files or complex concepts. -[![CI](https://github.com/Kaliumhexacyanoferrat/GenHTTP/actions/workflows/ci.yml/badge.svg)](https://github.com/Kaliumhexacyanoferrat/GenHTTP/actions/workflows/ci.yml) [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=GenHTTP&metric=coverage)](https://sonarcloud.io/dashboard?id=GenHTTP) [![nuget Package](https://img.shields.io/nuget/v/GenHTTP.Core.svg)](https://www.nuget.org/packages/GenHTTP.Core/) [](https://discord.gg/cW6tPJS7nt) [![Discord](https://discordapp.com/api/guilds/1177529388229734410/widget.png?style=shield)](https://discord.gg/GwtDyUpkpV) +[![View - Documentation](https://img.shields.io/badge/view-Documentation-AB54FF)](https://genhttp.org/documentation/) [![nuget Package](https://img.shields.io/nuget/v/GenHTTP.Core.svg)](https://www.nuget.org/packages/GenHTTP.Core/) [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=GenHTTP&metric=coverage)](https://sonarcloud.io/dashboard?id=GenHTTP) [![Discord](https://discordapp.com/api/guilds/1177529388229734410/widget.png?style=shield)](https://discord.gg/GwtDyUpkpV) ## 🚀 Features @@ -16,6 +16,18 @@ the functionality rather than on messing around with configuration files or comp - [Optimized](https://genhttp.org/features/) out of the box, small memory and storage [footprint](https://genhttp.org/features/#footprint) - Grade A+ security level according to SSL Labs +## 💻 Supported Platforms + +GenHTTP targets all .NET versions currently [supported by Microsoft](https://dotnet.microsoft.com/en-us/platform/support/policy/dotnet-core). +Major versions are released once a year, following the .NET release cycle. +Additionally, our automated tests ensure full compatibility on the following platforms: + +| OS | Architectures | +|---------|-------------------------| +| Linux | `x64`, `arm32`, `arm64` | +| Windows | `x64`, `arm64` | +| macOS | `x64`, `arm64` | + ## 📖 Getting Started This section shows how to create a new project from scratch using project templates and how to extend your existing @@ -123,9 +135,3 @@ in C#. In 2024 the focus has shifted towards API development, dropping support f - Powered by [.NET](https://github.com/dotnet/core) - Modules implemented with [NSwag](https://github.com/RicoSuter/NSwag) (Open API), [Fleck](https://github.com/statianzo/Fleck) (WebSockets) - -## 👥 Contributors - - - - diff --git a/Testing/Acceptance/Engine/Kestrel/CustomizingTests.cs b/Testing/Acceptance/Engine/Kestrel/CustomizingTests.cs index a272a6d7e..0c82aa199 100644 --- a/Testing/Acceptance/Engine/Kestrel/CustomizingTests.cs +++ b/Testing/Acceptance/Engine/Kestrel/CustomizingTests.cs @@ -5,12 +5,14 @@ namespace GenHTTP.Testing.Acceptance.Engine.Kestrel; [TestClass] -public class CustomizingTests +public class CustomizingTests : KestrelBaseTest { [TestMethod] public async Task TestHooks() { + if (!CheckKestrel()) return; + var configHook = (WebApplicationBuilder b) => { }; var appHook = (WebApplication a) => { }; diff --git a/Testing/Acceptance/Engine/Kestrel/KestrelBaseTest.cs b/Testing/Acceptance/Engine/Kestrel/KestrelBaseTest.cs new file mode 100644 index 000000000..a48e2e565 --- /dev/null +++ b/Testing/Acceptance/Engine/Kestrel/KestrelBaseTest.cs @@ -0,0 +1,8 @@ +namespace GenHTTP.Testing.Acceptance.Engine.Kestrel; + +public class KestrelBaseTest +{ + + protected bool CheckKestrel() => Environment.GetEnvironmentVariable("TEST_ENGINE") == null; + +} diff --git a/Testing/Acceptance/Engine/Kestrel/LifecycleTests.cs b/Testing/Acceptance/Engine/Kestrel/LifecycleTests.cs index 169442c7e..fe2b081d4 100644 --- a/Testing/Acceptance/Engine/Kestrel/LifecycleTests.cs +++ b/Testing/Acceptance/Engine/Kestrel/LifecycleTests.cs @@ -4,12 +4,14 @@ namespace GenHTTP.Testing.Acceptance.Engine.Kestrel; [TestClass] -public class LifecycleTests +public class LifecycleTests : KestrelBaseTest { [TestMethod] public async Task TestLifecycle() { + if (!CheckKestrel()) return; + var handler = Content.From(Resource.FromString("Hello Kestrel!")).Build(); await using var host = new TestHost(handler, engine: TestEngine.Kestrel); diff --git a/Testing/Acceptance/Engine/Kestrel/MappingTests.cs b/Testing/Acceptance/Engine/Kestrel/MappingTests.cs index 284dc5d5a..fff7e7a47 100644 --- a/Testing/Acceptance/Engine/Kestrel/MappingTests.cs +++ b/Testing/Acceptance/Engine/Kestrel/MappingTests.cs @@ -5,12 +5,14 @@ namespace GenHTTP.Testing.Acceptance.Engine.Kestrel; [TestClass] -public class MappingTests +public class MappingTests : KestrelBaseTest { [TestMethod] public async Task TestHeaders() { + if (!CheckKestrel()) return; + var app = Inline.Create().Get((IRequest request) => { var count = request.Headers.Count; @@ -37,6 +39,8 @@ public async Task TestHeaders() [TestMethod] public async Task TestQuery() { + if (!CheckKestrel()) return; + var app = Inline.Create().Get((IRequest request) => { var count = request.Query.Count; @@ -63,6 +67,8 @@ public async Task TestQuery() [TestMethod] public async Task TestConnection() { + if (!CheckKestrel()) return; + var app = Inline.Create().Get((IRequest request) => { Assert.IsNotNull(request.Client.Host); diff --git a/Testing/Acceptance/Engine/Kestrel/ProtocolTests.cs b/Testing/Acceptance/Engine/Kestrel/ProtocolTests.cs index a72e3f376..9bf8b950b 100644 --- a/Testing/Acceptance/Engine/Kestrel/ProtocolTests.cs +++ b/Testing/Acceptance/Engine/Kestrel/ProtocolTests.cs @@ -8,12 +8,14 @@ namespace GenHTTP.Testing.Acceptance.Engine.Kestrel; [TestClass] -public class ProtocolTests +public class ProtocolTests : KestrelBaseTest { [TestMethod] public async Task TestHttp2And3() { + if (!CheckKestrel()) return; + var logic = Inline.Create().Get((IRequest request) => request.ProtocolType); var client = GetClient(); diff --git a/Testing/Acceptance/MultiEngineTest.cs b/Testing/Acceptance/MultiEngineTest.cs index 8d0568496..fe0e12336 100644 --- a/Testing/Acceptance/MultiEngineTest.cs +++ b/Testing/Acceptance/MultiEngineTest.cs @@ -13,11 +13,25 @@ public class MultiEngineTestAttribute : Attribute, ITestDataSource public IEnumerable GetData(MethodInfo methodInfo) { - return new List + var engine = Environment.GetEnvironmentVariable("TEST_ENGINE"); + + if (engine == null) { + return new List + { + new object[] { TestEngine.Internal }, + new object[] { TestEngine.Kestrel } + }; + } + + if (Enum.TryParse(engine, out TestEngine found)) { - new object[] { TestEngine.Internal }, - new object[] { TestEngine.Kestrel } - }; + return new List + { + new object[] { found } + }; + } + + throw new InvalidOperationException($"Engine '{engine}' is not supported"); } public string GetDisplayName(MethodInfo methodInfo, object?[]? data)