using System.Globalization; using System.Text; using System.Text.RegularExpressions; using MBN_STOCK_WEBVIEW.Infrastructure; using MMoneyCoderSharp.Data; Console.OutputEncoding = Encoding.UTF8; using var cancellation = new CancellationTokenSource(TimeSpan.FromMinutes(3)); Console.CancelKeyPress += (_, eventArgs) => { eventArgs.Cancel = true; cancellation.Cancel(); }; var configurationPath = GetConfigurationPath(args); try { var runtime = DatabaseRuntime.CreateDefault(configurationPath); var statuses = await runtime.HealthService.CheckAllAsync(cancellation.Token); foreach (var status in statuses) { Console.WriteLine( $"{status.Source}: {status.State} ({status.Elapsed.TotalMilliseconds:F0} ms) - {status.UserMessage}"); } if (statuses.Any(status => status.State != DatabaseHealthState.Healthy)) { Console.Error.WriteLine("Smoke test stopped because both database health probes must be healthy."); return 2; } await VerifyOracleServerVersionAsync(runtime.Executor, cancellation.Token); var service = new LegacyMarketDataService(runtime.Executor); await VerifySnapshotAsync(service, MarketDataView.Kospi, cancellation.Token); await VerifySnapshotAsync(service, MarketDataView.Kosdaq, cancellation.Token); await VerifySnapshotAsync(service, MarketDataView.Index, cancellation.Token); await VerifySnapshotAsync(service, MarketDataView.Overseas, cancellation.Token); Console.WriteLine("REAL_DB_SMOKE: PASS"); return 0; } catch (OperationCanceledException) { Console.Error.WriteLine("REAL_DB_SMOKE: CANCELED_OR_TIMED_OUT"); return 3; } catch (DatabaseInfrastructureException exception) { Console.Error.WriteLine($"REAL_DB_SMOKE: FAIL - {exception.Message}"); return 1; } catch { Console.Error.WriteLine("REAL_DB_SMOKE: FAIL - An unexpected error occurred. No provider details were printed."); return 1; } static string? GetConfigurationPath(string[] arguments) { if (arguments.Length == 0) { return null; } if (arguments.Length == 2 && arguments[0].Equals("--config", StringComparison.OrdinalIgnoreCase)) { return arguments[1]; } throw new DatabaseConfigurationException("Usage: MBN_STOCK_WEBVIEW.DbSmoke [--config ]"); } static async Task VerifyOracleServerVersionAsync( IDataQueryExecutor executor, CancellationToken cancellationToken) { const string query = "SELECT VERSION FROM PRODUCT_COMPONENT_VERSION " + "WHERE PRODUCT LIKE 'Oracle Database%' FETCH FIRST 1 ROWS ONLY"; var table = await executor.ExecuteAsync( DataSourceKind.Oracle, "OracleVersion", query, cancellationToken); if (table.Rows.Count == 0 || table.Columns.Count == 0) { throw new DatabaseConfigurationException("Oracle 서버 버전을 확인할 수 없습니다."); } var version = Convert.ToString(table.Rows[0][0], CultureInfo.InvariantCulture) ?? string.Empty; var match = Regex.Match(version, @"(?\d{2})(?:\.\d+)", RegexOptions.CultureInvariant); if (!match.Success || !int.TryParse(match.Groups["major"].Value, NumberStyles.None, CultureInfo.InvariantCulture, out var major)) { throw new DatabaseConfigurationException("Oracle 서버 주 버전을 판별할 수 없습니다."); } Console.WriteLine($"Oracle server major version: {major}"); if (major < 19) { throw new DatabaseConfigurationException( "Oracle.ManagedDataAccess.Core 23.26.200은 Oracle Database 19c 이상이 필요합니다."); } } static async Task VerifySnapshotAsync( IMarketDataService service, MarketDataView view, CancellationToken cancellationToken) { var snapshot = await service.GetAsync(view, maximumRowsPerTable: 5, cancellationToken); if (snapshot.Tables.Count == 0) { throw new DatabaseConfigurationException($"{view} 조회 결과에 데이터셋이 없습니다."); } foreach (var table in snapshot.Tables) { if (table.Columns.Count == 0) { throw new DatabaseConfigurationException($"{view}/{table.Name} 결과 열이 없습니다."); } Console.WriteLine( $"{view}/{table.Source}/{table.Name}: {table.TotalRowCount.ToString(CultureInfo.InvariantCulture)} rows"); } }