using System.Text.Json; using Omika.Core.Compatibility; using Omika.Data.Connection; using Omika.Data.HfSql.Connection; using Omika.Data.SchemaDetection; namespace Omika.Tests.Connection; /// /// Tests d'intégration OLE DB HFSQL réels. /// /// Ces tests nécessitent un serveur HFSQL accessible et le provider OLE DB /// PCSOFT.HFSQL installé. Ils sont ignorés automatiquement si la /// configuration locale n'est pas disponible ou si le serveur est injoignable. /// /// Aucun secret n'est affiché : les assertions portent uniquement sur les /// modes d'accès observés. /// public class HfSqlOleDbIntegrationTests { private const string ConfigPath = @"D:\Avalonia\Omika\config\hfsql-test.local.json"; private sealed class TestConfig { public int Port { get; set; } public string Server { get; set; } = ""; public string ProtectionPlusSecret { get; set; } = ""; public FilePasswordsConfig FilePasswords { get; set; } = new(); public DatabaseConfig Batik { get; set; } = new(); public DatabaseConfig Omika { get; set; } = new(); } private sealed class FilePasswordsConfig { public string? ProtectionStd { get; set; } public string? ProtectionPlus { get; set; } } private sealed class DatabaseConfig { public string Credential { get; set; } = ""; public string Database { get; set; } = ""; public string User { get; set; } = ""; public string? OriginalDatabaseName { get; set; } } private static TestConfig? LoadConfig() { if (!File.Exists(ConfigPath)) return null; try { var json = File.ReadAllText(ConfigPath); return JsonSerializer.Deserialize( json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); } catch { return null; } } private static HfSqlConnectionOptions BuildOptions(TestConfig config, DatabaseConfig db) { return new HfSqlConnectionOptions { Server = config.Server, Port = config.Port, Database = db.Database, User = db.User, Credential = db.Credential, FilePasswords = new HfSqlFilePasswordOptions { ProtectionStd = config.FilePasswords.ProtectionStd, ProtectionPlus = config.FilePasswords.ProtectionPlus } }; } [Fact] public async Task ResolveAsync_Batik_Client_IsAccessible() { var config = LoadConfig(); if (config is null) return; // config absente : test ignoré var options = BuildOptions(config, config.Batik); var factory = new HfSqlOleDbConnectionFactory(); var resolver = new HfSqlFileAccessResolver(factory, options); var files = new List { new() { LogicalFile = "Client", ExpectedGroup = "ProtectionStd" } }; try { var result = await resolver.ResolveAsync(files); Assert.True(result["Client"].IsAccessible, $"Client Batik doit être accessible (mode observé : {result["Client"].ObservedAccess})"); } catch (Exception ex) when (IsServerUnavailable(ex)) { return; // serveur injoignable : test ignoré } } [Fact] public async Task ResolveAsync_Omika_Client_IsAccessible() { var config = LoadConfig(); if (config is null) return; var options = BuildOptions(config, config.Omika); var factory = new HfSqlOleDbConnectionFactory(); var resolver = new HfSqlFileAccessResolver(factory, options); var files = new List { new() { LogicalFile = "Client", ExpectedGroup = "ProtectionStd" } }; try { var result = await resolver.ResolveAsync(files); Assert.True(result["Client"].IsAccessible, $"Client Omika doit être accessible (mode observé : {result["Client"].ObservedAccess})"); } catch (Exception ex) when (IsServerUnavailable(ex)) { return; } } // --- Détection de schéma réelle (BATIK_TEST / OMIKA_TEST) ----------------- [Fact] public async Task DetectAsync_BatikTest_ReturnsBatik() { var config = LoadConfig(); if (config is null) return; // config absente : test ignoré var options = BuildOptions(config, config.Batik); var factory = new HfSqlOleDbConnectionFactory(); await using var connection = new HfSqlOleDbConnection(factory, options); var detector = new DatabaseSchemaDetector(connection); try { var result = await detector.DetectAsync(); Assert.True(result.IsSuccess, $"La détection Batik a échoué : {string.Join("; ", result.Errors)}"); Assert.Equal(DatabaseSchemaVersion.Batik, result.Value); } catch (Exception ex) when (IsServerUnavailable(ex)) { return; // serveur injoignable : test ignoré } } [Fact] public async Task DetectAsync_OmikaTest_ReturnsOmika() { var config = LoadConfig(); if (config is null) return; // config absente : test ignoré var options = BuildOptions(config, config.Omika); var factory = new HfSqlOleDbConnectionFactory(); await using var connection = new HfSqlOleDbConnection(factory, options); var detector = new DatabaseSchemaDetector(connection); try { var result = await detector.DetectAsync(); Assert.True(result.IsSuccess, $"La détection Omika a échoué : {string.Join("; ", result.Errors)}"); Assert.Equal(DatabaseSchemaVersion.Omika, result.Value); } catch (Exception ex) when (IsServerUnavailable(ex)) { return; // serveur injoignable : test ignoré } } private static bool IsServerUnavailable(Exception ex) { // Le provider OLE DB peut lever des exceptions natives au teardown. // On ignore les erreurs de connexion (serveur injoignable) mais on // propage les erreurs de logique. var message = ex.Message; return message.Contains("provider", StringComparison.OrdinalIgnoreCase) || message.Contains("serveur", StringComparison.OrdinalIgnoreCase) || message.Contains("server", StringComparison.OrdinalIgnoreCase) || message.Contains("connexion", StringComparison.OrdinalIgnoreCase) || message.Contains("connection", StringComparison.OrdinalIgnoreCase) || message.Contains("E_FAIL", StringComparison.OrdinalIgnoreCase) || message.Contains("0x80004005", StringComparison.OrdinalIgnoreCase); } }