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
95 changes: 95 additions & 0 deletions .github/workflows/pr-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
name: PR Check

on:
pull_request:
branches: [develop, master]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Include main in pull_request branch filter

This workflow only runs for PRs targeting develop or master, so pull requests into main will skip all CI checks from this file. In repositories where main is the active integration branch, this silently removes build/test coverage on incoming changes and lets regressions merge without the intended gate.

Useful? React with 👍 / 👎.

workflow_dispatch:

jobs:
dotnet-build:
name: .NET Build
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'

- name: Restore dependencies
run: dotnet restore

- name: Build
run: dotnet build --configuration Release --no-restore

dotnet-test:
name: .NET Test
runs-on: ubuntu-latest
needs: dotnet-build

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'

- name: Restore dependencies
run: dotnet restore

- name: Build
run: dotnet build --configuration Release --no-restore

- name: Test
run: dotnet test OpenLibraryRent.Tests --configuration Release --no-build --verbosity normal

npm-build:
name: npm Build
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
cache-dependency-path: OpenLibraryRent/OpenLibraryRent.Client/package-lock.json

- name: Install dependencies
working-directory: OpenLibraryRent/OpenLibraryRent.Client
run: npm ci

- name: Build
working-directory: OpenLibraryRent/OpenLibraryRent.Client
run: npm run build

npm-check:
name: npm Check
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
cache-dependency-path: OpenLibraryRent/OpenLibraryRent.Client/package-lock.json

- name: Install dependencies
working-directory: OpenLibraryRent/OpenLibraryRent.Client
run: npm ci

- name: Svelte Check
working-directory: OpenLibraryRent/OpenLibraryRent.Client
run: npm run check
79 changes: 79 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: Release

on:
push:
branches: [master]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Trigger release workflow from main branch

The release job is configured to run only on pushes to master, so pushes to main will never publish artifacts or create a GitHub Release. If main is used for production merges, this breaks the automated release path entirely until someone runs the workflow manually.

Useful? React with 👍 / 👎.

workflow_dispatch:

permissions:
contents: write

jobs:
build-and-release:
name: Build and Release
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
cache-dependency-path: OpenLibraryRent/OpenLibraryRent.Client/package-lock.json

- name: Install npm dependencies
working-directory: OpenLibraryRent/OpenLibraryRent.Client
run: npm ci

- name: Build frontend
working-directory: OpenLibraryRent/OpenLibraryRent.Client
run: npm run build

- name: Restore .NET dependencies
run: dotnet restore

- name: Build .NET
run: dotnet build --configuration Release --no-restore

- name: Publish
run: dotnet publish OpenLibraryRent/OpenLibraryRent.csproj --configuration Release --no-build --output ./publish

- name: Create version tag
id: version
run: |
VERSION=$(date +'%Y.%m.%d')-${{ github.run_number }}
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Version: $VERSION"

- name: Create ZIP archive
run: |
cd publish
zip -r ../OpenLibraryRent-${{ steps.version.outputs.version }}.zip .
cd ..

- name: Create Release
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ steps.version.outputs.version }}
name: Release v${{ steps.version.outputs.version }}
body: |
## OpenLibraryRent Release v${{ steps.version.outputs.version }}

**Changes:**
${{ github.event.head_commit.message }}

**Commit:** ${{ github.sha }}
files: |
OpenLibraryRent-${{ steps.version.outputs.version }}.zip
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
27 changes: 27 additions & 0 deletions OpenLibraryRent.Tests/OpenLibraryRent.Tests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="10.0.0-*" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageReference Include="Moq" Version="4.20.72" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.4" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\OpenLibraryRent\OpenLibraryRent.csproj" />
</ItemGroup>

<ItemGroup>
<Using Include="Xunit" />
</ItemGroup>

</Project>
120 changes: 120 additions & 0 deletions OpenLibraryRent.Tests/Services/Caching/CacheKeysTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
using OpenLibraryRent.Services.Caching;
using Xunit;

namespace OpenLibraryRent.Tests.Services.Caching;

public class CacheKeysTests
{
[Fact]
public void TenantInfo_Returns_Correct_Format()
{
// Arrange
var tenantId = "tenant-123";

// Act
var key = CacheKeys.TenantInfo(tenantId);

// Assert
Assert.Equal("OpenLibraryRent:tenant:tenant-123:info", key);
}

[Fact]
public void TenantSettings_Returns_Correct_Format()
{
// Arrange
var tenantId = "tenant-456";

// Act
var key = CacheKeys.TenantSettings(tenantId);

// Assert
Assert.Equal("OpenLibraryRent:tenant:tenant-456:settings", key);
}

[Fact]
public void BookByIsbn_Returns_Correct_Format()
{
// Arrange
var isbn = "978-4-123456-78-9";

// Act
var key = CacheKeys.BookByIsbn(isbn);

// Assert
Assert.Equal("OpenLibraryRent:book:isbn:978-4-123456-78-9", key);
}

[Fact]
public void UserPermissions_Returns_Correct_Format()
{
// Arrange
var tenantId = "tenant-123";
var userId = "user-456";

// Act
var key = CacheKeys.UserPermissions(tenantId, userId);

// Assert
Assert.Equal("OpenLibraryRent:tenant:tenant-123:user:user-456:permissions", key);
}

[Fact]
public void TenantAll_Returns_Correct_Pattern_Format()
{
// Arrange
var tenantId = "tenant-123";

// Act
var pattern = CacheKeys.TenantAll(tenantId);

// Assert
Assert.Equal("OpenLibraryRent:tenant:tenant-123:*", pattern);
}

[Theory]
[InlineData("tenant-1")]
[InlineData("abc123")]
[InlineData("test-tenant-id")]
public void TenantInfo_Consistent_For_Same_TenantId(string tenantId)
{
// Act
var key1 = CacheKeys.TenantInfo(tenantId);
var key2 = CacheKeys.TenantInfo(tenantId);

// Assert
Assert.Equal(key1, key2);
}

[Fact]
public void CacheKeys_Are_Deterministic()
{
// Arrange
var tenantId = "test";
var isbn = "1234567890";
var userId = "user1";

// Act - Call multiple times
var tenantKey1 = CacheKeys.TenantInfo(tenantId);
var tenantKey2 = CacheKeys.TenantInfo(tenantId);
var bookKey1 = CacheKeys.BookByIsbn(isbn);
var bookKey2 = CacheKeys.BookByIsbn(isbn);
var permKey1 = CacheKeys.UserPermissions(tenantId, userId);
var permKey2 = CacheKeys.UserPermissions(tenantId, userId);

// Assert - Same inputs produce same keys
Assert.Equal(tenantKey1, tenantKey2);
Assert.Equal(bookKey1, bookKey2);
Assert.Equal(permKey1, permKey2);
}

[Fact]
public void Different_Inputs_Produce_Different_Keys()
{
// Arrange & Act
var key1 = CacheKeys.TenantInfo("tenant-1");
var key2 = CacheKeys.TenantInfo("tenant-2");

// Assert
Assert.NotEqual(key1, key2);
}
}
Loading
Loading