Commit Graph

56 Commits

Author SHA1 Message Date
Joseph Doherty 832911c5f2 test(db): add validation stored procedure tests 2026-01-06 13:48:16 -05:00
Joseph Doherty 795c15df56 feat(datasync): add EtlPipelineFactory with JSON config support
- Implement IEtlPipelineFactory with ForTable() method returning a builder
- Load pipeline config from JSON file path (from PipelineOptions)
- Parse config using System.Text.Json with PropertyNameCaseInsensitive
- Builder supports WithMode() and WithMinimumDate() fluent methods
- Create DbQuerySource for source with ParameterFormatConverter for JDE dates
- Create DbBulkMergeDestination or DbBulkImportDestination based on sync mode
- Mass mode defaults to bulkImport, incremental defaults to bulkMerge
- Support destination override in sync mode config
- Execute pre/post scripts from config (prePurge, reIndex, custom scripts)
- Validate config: require mass and incremental modes, reject runtime params
- Add comprehensive tests for factory, builder, and config validation
2026-01-06 13:45:36 -05:00
Joseph Doherty afb6ad4f09 test(db): add complex table extraction function tests 2026-01-06 13:44:32 -05:00
Joseph Doherty e0d0ffa8fc test(db): add simple table extraction function tests
Add comprehensive tests for the 5 simple table extraction functions:
- fn_GetSearchWorkOrders
- fn_GetSearchItemNumbers
- fn_GetSearchProfitCenters
- fn_GetSearchWorkCenters
- fn_GetSearchOperatorIDs

Each function tested for:
- Valid array returns all values
- Empty array returns empty
- Missing property returns empty
- Search not found returns empty
- NULL criteria returns empty
- Invalid JSON returns empty
- Bad type values (nulls) filtered out

Additional edge case tests for large arrays and long values.
Total: 38 tests (7 per function + 2 additional edge cases).
2026-01-06 13:40:22 -05:00
Joseph Doherty 13ae0091dd test(db): add scalar extraction function tests
Tests all 3 scalar functions:
- fn_GetSearchMinimumDt
- fn_GetSearchMaximumDt
- fn_GetSearchExtractMisData

Test cases cover:
- Valid JSON extraction
- Missing property returns NULL
- Search not found returns NULL
- NULL criteria returns NULL
- Invalid JSON returns NULL

Uses DatabaseTestBase infrastructure with FluentAssertions and Dapper.
2026-01-06 13:36:12 -05:00
Joseph Doherty 8af4f9915f feat(datasync): extend DbBulkMergeDestination with excludeFromUpdate and updateCondition 2026-01-06 13:35:25 -05:00
Joseph Doherty 61f927bd0e feat(tests): add database test infrastructure
Add DatabaseTestBase.cs with xUnit Collection for test isolation:
- DatabaseTestCollection disables parallel execution
- DatabaseTestFixture verifies database connectivity
- DatabaseTestBase provides connection and cleanup helpers
- InsertTestSearchAsync for creating test data with SearchCriteria
- InsertTestSearchWithRawCriteriaAsync for testing invalid JSON scenarios

Also adds required packages: Dapper, FluentAssertions, Microsoft.Data.SqlClient
2026-01-06 13:30:34 -05:00
Joseph Doherty eb85ab6f34 feat(datasync): add generic DbQuerySource for JDE/CMS/LotFinder
Extend DbQuerySource to support multiple connection types:
- Add connectionType parameter ("jde", "cms", "lotfinder")
- Use appropriate IDbConnectionFactory method for each type
- Support Dictionary<string, object> parameters
- Use DbConnection/DbCommand for cross-database compatibility
2026-01-06 13:30:00 -05:00
Joseph Doherty 1f7fd9f0f2 feat(datasync): add ParameterFormatConverter with JDE date/time support 2026-01-06 13:25:15 -05:00
Joseph Doherty bff947d1e8 test: add AuthApiClientIntegrationTests
Add 5 integration tests for AuthApiClient:
- GetPublicKeyAsync_ReturnsValidPublicKey
- LoginAsync_WithValidCredentials_ReturnsSuccess
- GetCurrentUserAsync_AfterLogin_ReturnsUserInfo
- GetCurrentUserAsync_WithoutAuth_ReturnsUnauthorized
- LogoutAsync_AfterLogin_InvalidatesSession

Tests use RSA encryption pattern for login credentials and
verify auth cookie behavior across requests.
2026-01-06 11:39:09 -05:00
Joseph Doherty f7e683703d test: add SearchApiClientIntegrationTests for search endpoint validation
Add integration tests for SearchApiClient covering:
- GetUserSearchesAsync with authentication returns success
- GetUserSearchesAsync without authentication returns unauthorized
- GetSearchAsync with non-existent ID returns not found
2026-01-06 11:37:43 -05:00
Joseph Doherty 54de0ce1c3 test: add LookupApiClientIntegrationTests for lookup endpoint validation
Add 4 integration tests for LookupApiClient that verify lookup endpoints
work correctly through the actual HTTP pipeline without authentication.
2026-01-06 11:37:36 -05:00
Joseph Doherty 3ed2d7324d test: add ClientIntegrationTestBase with shared auth HttpClient 2026-01-06 11:36:13 -05:00
Joseph Doherty 7e5ac56525 build: add Client project reference to integration tests
Add JdeScoping.Client project reference to Api.IntegrationTests
to enable testing API client classes against the real API.
2026-01-06 11:34:23 -05:00
Joseph Doherty 6cb852c164 test: add FileApiClientTests with route, success, and error tests
Add comprehensive unit tests for FileApiClient covering:
- Route verification tests for all 4 download endpoints (POST method)
- Route verification tests for 2 upload endpoints (POST method)
- Success tests for downloads returning byte arrays
- Success tests verifying existing data can be passed to downloads
- Success tests for uploads returning IReadOnlyList<T>
- Multipart content-type and filename verification test
- Error tests (404 for download, 400 validation error for upload)
2026-01-06 11:33:31 -05:00
Joseph Doherty 55bfdb3532 test: add AuthApiClientTests with route and success tests
Add unit tests for AuthApiClient covering:
- Route verification tests for GetPublicKey, Login, Logout, GetCurrentUser
- Success tests for all 4 methods
- Proper handling of 204 NoContent for Logout (returns Unit)
2026-01-06 11:31:49 -05:00
Joseph Doherty d06d5f27e2 test: add LookupApiClientTests with route and encoding tests
- Route verification tests for all 4 methods (FindItems, FindProfitCenters,
  FindWorkCenters, FindOperators)
- Query string encoding tests verifying special characters (&, =) and spaces
  are properly URL-encoded
- Success tests for all lookup methods verifying deserialization
- Representative error test for 500 status code
2026-01-06 11:29:46 -05:00
Joseph Doherty 76ce35458c test: add SearchApiClientTests with route and success/error tests
Add comprehensive unit tests for SearchApiClient covering:
- Route verification tests for all 6 methods (GetUserSearches, GetQueuedSearches,
  GetSearch, CopySearch, CreateSearch, GetResults)
- Success tests verifying deserialization for all methods
- Representative error tests (404 for GetSearch, 401 for GetUserSearches)

Uses MockHttpMessageHandler to verify correct API routes are called
and ApiResult<T> pattern maps responses correctly.
2026-01-06 11:27:33 -05:00
Joseph Doherty 299099f716 test: add POST and bytes tests to ApiClientBaseTests
Added 11 new tests covering:
- POST method tests (200 success, 401 unauthorized, no-body variant)
- Bytes tests (GET 200, GET 404, POST 200)
- Non-GET status code tests (POST 400 validation, bytes 500, multipart 401/200)

All 23 ApiClientBaseTests now pass.
2026-01-06 11:25:49 -05:00
Joseph Doherty c626ffbd69 test: add edge case tests to ApiClientBaseTests
Add 7 edge case tests for ApiClientBase:
- GetAsync_Returns200_EmptyBody_MapsToApiError
- GetAsync_Returns200_InvalidJson_MapsToApiError
- GetAsync_Returns204_ForUnitType_MapsToSuccess
- GetAsync_Returns204_ForNonUnitType_MapsToApiError
- GetAsync_NetworkException_MapsToApiError
- GetAsync_Timeout_MapsToApiError
- GetAsync_Returns400_WithoutValidationFormat_MapsToApiError

Also fix bug in ApiClientBase where 204 NoContent for Unit type
failed due to incorrect type casting. The implicit conversion from
Unit to ApiResult<Unit> must be applied before the runtime cast.
2026-01-06 11:23:54 -05:00
Joseph Doherty 6af5a4f9d6 test: add all 6 status code mapping tests to ApiClientBaseTests
- Add GetAsync_Returns404_MapsToNotFound test
- Add GetAsync_Returns400_WithValidationErrors_MapsToValidationError test
- Add GetAsync_Returns401_MapsToUnauthorized test
- Add GetAsync_Returns403_MapsToForbidden test
- Add GetAsync_Returns500_MapsToApiError test
- Add FrameworkReference to Microsoft.AspNetCore.App for ValidationProblemDetails
2026-01-06 11:20:43 -05:00
Joseph Doherty e75ebe1ffb test: add ApiClientBaseTests with 200 OK mapping test 2026-01-06 11:17:19 -05:00
Joseph Doherty 626b7a63f2 test: add TestableApiClient helper for ApiClientBase unit tests 2026-01-06 11:15:10 -05:00
Joseph Doherty a8f79c26b2 refactor: add ApiRoutes import to FileControllerIntegrationTests
Added using statement for JdeScoping.Core.ApiContracts. The existing
routes (/api/file/...) are left unchanged as they test legacy download
by cache key endpoints which differ from the new FileIO routes.
2026-01-06 11:13:55 -05:00
Joseph Doherty 13976dea3b refactor: use ApiRoutes constants in AuthenticationTests
Replace hardcoded route strings with ApiRoutes.* constants:
- ApiRoutes.Auth.PublicKey, Login, Logout, Me
- ApiRoutes.Search.Base
- ApiRoutes.Lookup.Items, ProfitCenters, WorkCenters, Operators
2026-01-06 11:12:17 -05:00
Joseph Doherty 81b07ce027 feat: extract DevEtl to JdeScoping.DataSync.Dev project
- Create JdeScoping.DataSync.Dev for sandbox testing ETL code
- Create JdeScoping.DataSync.Dev.Tests for associated tests
- Move 22 source files and 8 test files
- Update namespaces from DevEtl to Dev
- Add both projects to solution
2026-01-06 10:18:09 -05:00
Joseph Doherty 380ffb9a82 fix(test): correct connection string name and cache directory path 2026-01-03 16:42:11 -05:00
Joseph Doherty e04e81b178 test(datasync): add integration tests for BranchDevEtl
Add integration tests for the Branch development ETL pipeline:
- BranchDevEtlTests with tests for pipeline creation and execution
- Tests verify pipeline creates correctly and loads data from cache files
- Added appsettings.json with local connection string and cache directory
- Added necessary packages (Configuration.Json, SqlClient, Dapper)

Tests require local SQL Server and CACHED_DB_FILES directory with
branch.json.zstd to pass; tests silently skip if resources unavailable.
2026-01-03 16:38:11 -05:00
Joseph Doherty 7dcbacd5ca fix(etl): address Codex MCP review findings for Phase 2
- Filter MERGE SQL columns to only include columns that exist in destination
  (allColumns and updateColumns were using unfiltered source columns)
- Fix schema-qualified table names to use proper [schema].[table] format
  instead of wrapping entire name in single brackets
- Add empty column mapping validation to throw early if no columns intersect
- Add JdeDateTransformer output column collision detection in OnInitialize
- Add TODO comment for WithCommandTimeout (stored but not yet passed to
  destinations)
- Add tests for FormatQualifiedTableName and output column collision
2026-01-03 11:27:07 -05:00
Joseph Doherty fcd8b660fa feat(etl): add WithCommandTimeout to EtlPipelineBuilder with validation 2026-01-03 11:09:28 -05:00
Joseph Doherty 3145fca371 feat(etl): add column mapping to destinations (intersect with dest schema) 2026-01-03 11:06:38 -05:00
Joseph Doherty 0b317c1ffc feat(etl): add commandTimeoutSeconds to destinations 2026-01-03 11:01:12 -05:00
Joseph Doherty 0e07a76438 feat(etl): add ParseTableName and QUOTENAME to CommonScripts
- Add ParseTableName method to parse table names with optional schema
  - Supports: "Table", "dbo.Table", "[dbo].[Table]"
  - Returns (schema, table) tuple, defaults to "dbo" schema
- Update DisableIndexes, RebuildIndexes, UpdateStatistics to:
  - Use QUOTENAME() for SQL injection protection
  - Pass schema and table as parameters via SqlScriptRunner
  - Support non-dbo schemas
- Update CustomSql to accept optional parameters and timeout
- Add comprehensive tests for ParseTableName with various formats
2026-01-03 10:56:05 -05:00
Joseph Doherty 40e458148d feat(etl): add parameters support to SqlScriptRunner 2026-01-03 10:52:33 -05:00
Joseph Doherty 0820a9b024 feat(etl): add collision detection to ColumnRenameTransformer 2026-01-03 10:50:03 -05:00
Joseph Doherty ae84cb3d75 feat(etl): add MapOrdinal and date validation with sentinel to JdeDateTransformer
- Add DefaultInvalidDateSentinel (1900-01-01) for invalid date handling
- Add optional invalidDateSentinel constructor parameter
- Add MapOrdinal override returning -1 for computed DateTime column
- Add GetDataTypeName override returning "datetime" for computed column
- Update ParseJdeDateTime with comprehensive validation:
  - Validate date is positive
  - Validate century (0 or 1)
  - Validate year (0-99)
  - Validate day of year (1-366 and respects leap year)
  - Validate time components (hours 0-23, minutes/seconds 0-59)
- Add tests for all new functionality
2026-01-03 10:46:19 -05:00
Joseph Doherty 577e67ec64 feat(etl): add MapOrdinal override to ColumnDropTransformer 2026-01-03 10:35:54 -05:00
Joseph Doherty 506ba5c61d feat(etl): add binary method overrides to DataTransformerBase
Add virtual methods to DataTransformerBase for GetBytes, GetChars,
GetData, and GetDataTypeName that properly handle computed columns
by throwing NotSupportedException when MapOrdinal returns -1.

Update TransformingDataReader to delegate these methods to the
transformer instead of directly to the source reader.
2026-01-03 10:33:13 -05:00
Joseph Doherty f5468d019f feat(etl): add MapOrdinal to IDataTransformer interface
Add MapOrdinal method to the IDataTransformer interface and provide
a default implementation in DataTransformerBase. This enables
transformers to report the mapping between transformed ordinals and
source ordinals, supporting use cases like computed columns which
return -1 to indicate no source ordinal.

- Add MapOrdinal(int, IDataReader) to IDataTransformer interface
- Add virtual MapOrdinal implementation in DataTransformerBase
- Add DataTransformerBaseTests with test for default behavior
2026-01-03 10:28:49 -05:00
Joseph Doherty 4c16e62661 feat(etl): implement EtlPipeline and EtlPipelineBuilder
Add pipeline orchestration for ETL operations:
- EtlPipeline: executes source -> transform -> destination flow
- EtlPipelineBuilder: fluent builder for pipeline configuration
- Supports pre/post scripts, multiple transformers
- Returns PipelineResult with step-by-step timing
2026-01-03 09:31:32 -05:00
Joseph Doherty 644e884b21 feat(etl): implement DbBulkMergeDestination for incremental updates 2026-01-03 09:26:43 -05:00
Joseph Doherty 63a0e7cf7e feat(etl): implement DbBulkImportDestination for full table refresh
Add bulk import destination that truncates and loads data using
SqlBulkCopy with configurable batch sizes and streaming support.
2026-01-03 09:22:57 -05:00
Joseph Doherty 8594baf11d feat(etl): implement DbQuerySource for database queries
Adds DbQuerySource, an IImportSource implementation that executes SQL
queries against the LotFinder database. Supports parameterized queries
using anonymous objects and configurable command timeouts.
2026-01-03 09:18:58 -05:00
Joseph Doherty 74c3f37446 feat(etl): implement JdeDateTransformer for Julian date parsing
Add transformer that combines JDE Julian date (CYYDDD) and time (HHMMSS)
columns into a single DateTime column. Includes static ParseJdeDateTime
method for direct date conversion.
2026-01-03 09:16:11 -05:00
Joseph Doherty 81cb0df6bf feat(etl): implement ColumnRenameTransformer
Add transformer for renaming columns in the data stream during ETL.
Supports case-insensitive column name matching and multiple renames.
2026-01-03 09:13:02 -05:00
Joseph Doherty f1b7809a45 feat(etl): implement ColumnDropTransformer
Add a data transformer that removes specified columns from the data stream.
Columns are matched by name (case-insensitive) and multiple columns can be
dropped in a single transformer. Includes comprehensive tests using NSubstitute
for mock IDataReader.
2026-01-03 09:10:54 -05:00
Joseph Doherty 6e7bcadf68 feat(etl): implement TransformingDataReader and DataTransformerBase
Add core transformer infrastructure for the ETL pipeline:
- DataTransformerBase: abstract base class with virtual methods for
  field count, names, types, values, ordinals, and null checking
- TransformingDataReader: IDataReader wrapper that delegates to
  transformer, enabling on-the-fly data transformations
2026-01-03 09:08:17 -05:00
Joseph Doherty c644b578ba feat(etl): add CommonScripts factory for index and statistics scripts 2026-01-03 09:05:13 -05:00
Joseph Doherty 82573df023 feat(etl): implement SqlScriptRunner
Add SqlScriptRunner class that implements IScriptRunner for executing
SQL scripts against the LotFinderDB cache database. Includes constructor
validation and configurable timeout support (default 1 hour).
2026-01-03 09:03:14 -05:00
Joseph Doherty dac3d216fd feat(etl): add result models for pipeline execution 2026-01-03 08:58:06 -05:00