Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 11 additions & 42 deletions .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,60 +15,29 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.0.x'

# Add NuGet Sources
dotnet-version: '10.0.x'

- name: Create Local NuGet Directory
run: mkdir ~/nuget

- name: Add Local Nuget Source
run: dotnet nuget add source ~/nuget

- name: Add Garage Group NuGet Source
run: >
dotnet nuget add source ${{ vars.GG_NUGET_SOURCE_URL }}
-n garage
-u ${{ secrets.GG_NUGET_SOURCE_USER_NAME }}
-p ${{ secrets.GG_NUGET_SOURCE_USER_PASSWORD }}
--store-password-in-clear-text

# Api.Contract

- name: Restore Api.Contract
run: dotnet restore ./src/*/Api.Contract.csproj

- name: Build Api.Contract
run: dotnet build ./src/*/Api.Contract.csproj --no-restore -c Release

- name: Pack Api.Contract
run: dotnet pack ./src/*/Api.Contract.csproj --no-restore -o ~/nuget -c Release

# Api

- name: Restore Api
run: dotnet restore ./src/*/Api.csproj

- name: Build Api
run: dotnet build ./src/*/Api.csproj --no-restore -c Release

- name: Pack Api
run: dotnet pack ./src/*/Api.csproj --no-restore -o ~/nuget -c Release
- name: Restore Infra.Http.Api
run: dotnet restore ./*/Infra.Http.Api.slnx

# Api.Test
- name: Build Infra.Http.Api
run: dotnet build ./*/Infra.Http.Api.slnx --no-restore -c Release

- name: Restore Api.Test
run: dotnet restore ./src/*/Api.Test.csproj
- name: Test Infra.Http.Api
run: dotnet test ./*/Infra.Http.Api.slnx --no-restore -c Release

- name: Test Api.Test
run: dotnet test ./src/*/Api.Test.csproj --no-restore -c Release
- name: Pack Infra.Http.Api
run: dotnet pack ./*/Infra.Http.Api.slnx --no-build -o ~/nuget -c Release

# Push

- name: Push Packages
if: ${{ github.ref == 'refs/heads/main' }}
run: >
dotnet nuget push "../../../nuget/*.nupkg"
-s ${{ vars.GG_NUGET_SOURCE_URL }}
-k ${{ secrets.GG_NUGET_SOURCE_USER_PASSWORD }}
-s https://api.nuget.org/v3/index.json
-k ${{ secrets.NUGET_SECRET }}
--skip-duplicate
10 changes: 5 additions & 5 deletions src/Api.Contract/Api.Contract.csproj
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable>
<InvariantGlobalization>true</InvariantGlobalization>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<NoWarn>$(NoWarn);IDE0130;CA1859</NoWarn>
<RootNamespace>GarageGroup.Infra</RootNamespace>
<AssemblyName>GarageGroup.Infra.Http.Api.Contract</AssemblyName>
<Version>0.3.0</Version>
<Version>1.0.0</Version>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="PrimeFuncPack.Core.Failure" Version="2.2.0" />
<PackageReference Include="PrimeFuncPack.Core.FlatArray" Version="1.5.0" />
<PackageReference Include="PrimeFuncPack.Core.FlatArray" Version="1.5.1" />
<PackageReference Include="PrimeFuncPack.Core.Result" Version="2.0.2" />
<PackageReference Include="PrimeFuncPack.Primitives.Strings" Version="2.0.3" />
<PackageReference Include="System.Memory.Data" Version="8.0.1" />
<PackageReference Include="PrimeFuncPack.Primitives.Strings" Version="3.0.0" />
<PackageReference Include="System.Memory.Data" Version="10.0.6" />
</ItemGroup>

</Project>
26 changes: 19 additions & 7 deletions src/Api.Contract/Input/HttpSendIn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,13 +109,25 @@ public override string ToString()
return builder.Append('\n').Append('\n').Append(body).ToString();
}

public static bool operator ==(HttpSendIn left, HttpSendIn right)
=>
left.Equals(right);
public static bool operator ==(HttpSendIn? left, HttpSendIn? right)
{
if (ReferenceEquals(left, right))
{
return true;
}

public static bool operator !=(HttpSendIn left, HttpSendIn right)
=>
left.Equals(right) is not true;
return left?.Equals(right) is true;
}

public static bool operator !=(HttpSendIn? left, HttpSendIn? right)
{
if (ReferenceEquals(left, right))
{
return false;
}

return left?.Equals(right) is not true;
}

private static FlatArray<KeyValuePair<string, string>> GetOrderedHeaders(FlatArray<KeyValuePair<string, string>> source)
{
Expand Down Expand Up @@ -163,4 +175,4 @@ static string GetKey(KeyValuePair<string, List<string>> kv)
=>
kv.Key;
}
}
}
22 changes: 14 additions & 8 deletions src/Api.Contract/Input/HttpVerb.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,17 @@ public bool Equals(HttpVerb? other)
return StringComparer.InvariantCultureIgnoreCase.Equals(Name, other.Name);
}

public static bool operator ==(HttpVerb left, HttpVerb right)
=>
left.Equals(right);

public static bool operator !=(HttpVerb left, HttpVerb right)
=>
left.Equals(right) is not true;
}
public static bool operator ==(HttpVerb? left, HttpVerb? right)
{
if (ReferenceEquals(left, right))
{
return true;
}

return left?.Equals(right) is true;
}

public static bool operator !=(HttpVerb? left, HttpVerb? right)
=>
(left == right) is false;
}
10 changes: 5 additions & 5 deletions src/Api.Test/Api.Test.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable>
<InvariantGlobalization>true</InvariantGlobalization>
Expand All @@ -17,13 +17,13 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.4.0" />
<PackageReference Include="xunit.v3" Version="3.2.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PackageReference Include="coverlet.collector" Version="8.0.1">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
Expand Down
87 changes: 87 additions & 0 deletions src/Api.Test/Test.HttpApi/HttpApiTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Xunit;

namespace GarageGroup.Infra.Http.Api.Test;

public static partial class HttpApiTest
{
public static TheoryData<HttpSuccessType, int, string?, bool, bool> SuccessCaseTestData
=>
new()
{
{ HttpSuccessType.Default, 201, "Created", true, true },
{ HttpSuccessType.OnlyHeaders, 200, "OK", true, false },
{ HttpSuccessType.OnlyStatusCode, 204, "No Content", false, false }
};

public static TheoryData<int, string?, string?, string?, string?> FailureCaseTestData
=>
new()
{
{ 404, "Not Found", "{\"error\":\"not found\"}", "application/json", "utf-8" },
{ 503, "Service Unavailable", "temporary outage", "text/plain", "us-ascii" }
};

private static HttpApi CreateApi(
Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> sendAsync,
HttpApiOption option = default)
{
if (option.BaseAddress is null)
{
option = option with
{
BaseAddress = new("https://example.com/")
};
}

return new(new DelegateHttpMessageHandler(sendAsync), option);
}

private sealed class DelegateHttpMessageHandler(
Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> sendAsync) : HttpMessageHandler
{
protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
=>
sendAsync(request, cancellationToken);
}

private static HttpResponseMessage CreateResponse(
int statusCode,
string? reasonPhrase,
IEnumerable<KeyValuePair<string, string>> headers,
string? body,
string? mediaType = null,
string? charSet = null)
{
var response = new HttpResponseMessage((System.Net.HttpStatusCode)statusCode)
{
ReasonPhrase = reasonPhrase
};

foreach (var header in headers)
{
response.Headers.Add(header.Key, header.Value);
}

if (body is null)
{
return response;
}

response.Content = new StringContent(body);
if (string.IsNullOrEmpty(mediaType) is false)
{
response.Content.Headers.ContentType = new(mediaType)
{
CharSet = charSet
};
}

return response;
}
}
34 changes: 34 additions & 0 deletions src/Api.Test/Test.HttpApi/Test.Constructor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Xunit;

namespace GarageGroup.Infra.Http.Api.Test;

partial class HttpApiTest
{
[Fact]
public static async Task Constructor_BaseAddressProvided_ExpectRequestUriCombined()
{
Uri? actualUri = null;

var source = CreateApi(
sendAsync: (request, _) =>
{
actualUri = request.RequestUri;
return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK));
},
option: new()
{
BaseAddress = new("https://example.com/root/")
});

_ = await source.SendAsync(
new(HttpVerb.Get, "products"),
TestContext.Current.CancellationToken);

Assert.Equal(new("https://example.com/root/products"), actualUri);
}
}
Loading
Loading