Add JSON config, DB-backed library options, and docs
- Add JSON-based config loading with XML fallback for DB and library options - Implement LibraryOptionsRepository with EF Core, migrations, and entity - Update CollectionFolder to use DB-backed options with XML fallback/backfill - Register repository in DI and initialize at startup - Use EF execution strategy for transactional DB operations - Suppress code analysis warnings in .csproj and test files - Add DATABASE_MIGRATION.md, LIBRARY_OPTIONS_DB_DESIGN.md, and WEBSOCKET_AUTHENTICATION.md - Add database.json.example and improve migration docs - Add tests for JSON config loader and update test naming warnings
This commit is contained in:
@@ -0,0 +1,203 @@
|
||||
// <copyright file="ConfigurationHelperTests.cs" company="PlaceholderCompany">
|
||||
// Copyright (c) PlaceholderCompany. All rights reserved.
|
||||
// </copyright>
|
||||
|
||||
namespace Emby.Server.Implementations.Tests.AppBase;
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using Emby.Server.Implementations.AppBase;
|
||||
using Jellyfin.Database.Implementations.DbConfiguration;
|
||||
using Jellyfin.Extensions.Json;
|
||||
using Xunit;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for the ConfigurationHelper JSON loading functionality.
|
||||
/// </summary>
|
||||
public class ConfigurationHelperTests
|
||||
{
|
||||
[Fact]
|
||||
public void GetJsonConfiguration_ValidJsonFile_DeserializesCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
var jsonPath = Path.Combine(tempDir, "test-config.json");
|
||||
|
||||
var testConfig = new DatabaseConfigurationOptions
|
||||
{
|
||||
DatabaseType = "Jellyfin-PostgreSQL",
|
||||
LockingBehavior = DatabaseLockingBehaviorTypes.NoLock
|
||||
};
|
||||
|
||||
Directory.CreateDirectory(tempDir);
|
||||
var json = JsonSerializer.Serialize(testConfig, JsonDefaults.Options);
|
||||
File.WriteAllText(jsonPath, json);
|
||||
|
||||
try
|
||||
{
|
||||
// Act
|
||||
var result = ConfigurationHelper.GetJsonConfiguration<DatabaseConfigurationOptions>(jsonPath);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal("Jellyfin-PostgreSQL", result.DatabaseType);
|
||||
Assert.Equal(DatabaseLockingBehaviorTypes.NoLock, result.LockingBehavior);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Cleanup
|
||||
if (Directory.Exists(tempDir))
|
||||
{
|
||||
Directory.Delete(tempDir, recursive: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetJsonConfiguration_MissingFile_CreatesDefaultAndReturnsIt()
|
||||
{
|
||||
// Arrange
|
||||
var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
var jsonPath = Path.Combine(tempDir, "test-config.json");
|
||||
|
||||
try
|
||||
{
|
||||
// Act
|
||||
var result = ConfigurationHelper.GetJsonConfiguration<DatabaseConfigurationOptions>(jsonPath);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.True(File.Exists(jsonPath), "JSON file should be created");
|
||||
|
||||
// Verify the file is valid JSON
|
||||
var fileContent = File.ReadAllText(jsonPath);
|
||||
var deserialized = JsonSerializer.Deserialize<DatabaseConfigurationOptions>(fileContent, JsonDefaults.Options);
|
||||
Assert.NotNull(deserialized);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Cleanup
|
||||
if (Directory.Exists(tempDir))
|
||||
{
|
||||
Directory.Delete(tempDir, recursive: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetJsonConfiguration_WithCustomProviderOptions_PreservesSettings()
|
||||
{
|
||||
// Arrange
|
||||
var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
var jsonPath = Path.Combine(tempDir, "test-config.json");
|
||||
|
||||
var testConfig = new DatabaseConfigurationOptions
|
||||
{
|
||||
DatabaseType = "Jellyfin-PostgreSQL",
|
||||
LockingBehavior = DatabaseLockingBehaviorTypes.Pessimistic,
|
||||
CustomProviderOptions = new CustomDatabaseOptions
|
||||
{
|
||||
PluginName = "Jellyfin-PostgreSQL",
|
||||
PluginAssembly = "Jellyfin.Database.Providers.Postgres",
|
||||
ConnectionString = "Host=localhost;Port=5432;Database=jellyfin;Username=jellyfin;Password=secret"
|
||||
}
|
||||
};
|
||||
|
||||
Directory.CreateDirectory(tempDir);
|
||||
var json = JsonSerializer.Serialize(testConfig, JsonDefaults.Options);
|
||||
File.WriteAllText(jsonPath, json);
|
||||
|
||||
try
|
||||
{
|
||||
// Act
|
||||
var result = ConfigurationHelper.GetJsonConfiguration<DatabaseConfigurationOptions>(jsonPath);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal("Jellyfin-PostgreSQL", result.DatabaseType);
|
||||
Assert.Equal(DatabaseLockingBehaviorTypes.Pessimistic, result.LockingBehavior);
|
||||
Assert.NotNull(result.CustomProviderOptions);
|
||||
Assert.Equal("Jellyfin-PostgreSQL", result.CustomProviderOptions.PluginName);
|
||||
Assert.Equal("Host=localhost;Port=5432;Database=jellyfin;Username=jellyfin;Password=secret",
|
||||
result.CustomProviderOptions.ConnectionString);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Cleanup
|
||||
if (Directory.Exists(tempDir))
|
||||
{
|
||||
Directory.Delete(tempDir, recursive: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetJsonConfiguration_InvalidJson_CreatesDefault()
|
||||
{
|
||||
// Arrange
|
||||
var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
var jsonPath = Path.Combine(tempDir, "test-config.json");
|
||||
|
||||
Directory.CreateDirectory(tempDir);
|
||||
File.WriteAllText(jsonPath, "{ invalid json");
|
||||
|
||||
try
|
||||
{
|
||||
// Act
|
||||
var result = ConfigurationHelper.GetJsonConfiguration<DatabaseConfigurationOptions>(jsonPath);
|
||||
|
||||
// Assert - should get default instance on invalid JSON
|
||||
Assert.NotNull(result);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Cleanup
|
||||
if (Directory.Exists(tempDir))
|
||||
{
|
||||
Directory.Delete(tempDir, recursive: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetJsonConfiguration_RoundTrip_PreservesData()
|
||||
{
|
||||
// Arrange
|
||||
var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
var jsonPath = Path.Combine(tempDir, "test-config.json");
|
||||
|
||||
var originalConfig = new DatabaseConfigurationOptions
|
||||
{
|
||||
DatabaseType = "Jellyfin-PostgreSQL",
|
||||
LockingBehavior = DatabaseLockingBehaviorTypes.Optimistic
|
||||
};
|
||||
|
||||
Directory.CreateDirectory(tempDir);
|
||||
|
||||
try
|
||||
{
|
||||
// Act - First load should create the file
|
||||
var result1 = ConfigurationHelper.GetJsonConfiguration<DatabaseConfigurationOptions>(jsonPath);
|
||||
|
||||
// Modify and verify round-trip
|
||||
var json = JsonSerializer.Serialize(originalConfig, JsonDefaults.Options);
|
||||
File.WriteAllText(jsonPath, json);
|
||||
|
||||
var result2 = ConfigurationHelper.GetJsonConfiguration<DatabaseConfigurationOptions>(jsonPath);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result2);
|
||||
Assert.Equal("Jellyfin-PostgreSQL", result2.DatabaseType);
|
||||
Assert.Equal(DatabaseLockingBehaviorTypes.Optimistic, result2.LockingBehavior);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Cleanup
|
||||
if (Directory.Exists(tempDir))
|
||||
{
|
||||
Directory.Delete(tempDir, recursive: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user