From e8ba022cbbafcbb7bb1565e9f1f093c5a964aa67 Mon Sep 17 00:00:00 2001 From: Hildebrando Chavez Date: Sat, 28 Feb 2026 17:31:52 -0600 Subject: [PATCH 1/4] Remove dotnet-tools.json and enable CI tests --- .config/dotnet-tools.json | 12 ------------ .github/workflows/build-ci.yml | 4 ++-- 2 files changed, 2 insertions(+), 14 deletions(-) delete mode 100644 .config/dotnet-tools.json diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json deleted file mode 100644 index 5bd5ffb..0000000 --- a/.config/dotnet-tools.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "version": 1, - "isRoot": true, - "tools": { - "electronnet.cli": { - "version": "23.6.1", - "commands": [ - "electronize" - ] - } - } -} \ No newline at end of file diff --git a/.github/workflows/build-ci.yml b/.github/workflows/build-ci.yml index 15ad937..42aee05 100644 --- a/.github/workflows/build-ci.yml +++ b/.github/workflows/build-ci.yml @@ -20,5 +20,5 @@ jobs: run: dotnet restore - name: Build run: dotnet build --no-restore -# - name: Test -# run: dotnet test --no-build --verbosity normal + - name: Test + run: dotnet test --no-build --verbosity normal From 8aabd429bea6b0e2f502b68463e7e2200a84ca98 Mon Sep 17 00:00:00 2001 From: Hildebrando Chavez Date: Sat, 28 Feb 2026 17:54:09 -0600 Subject: [PATCH 2/4] Exclude integration tests from CI test run Mark integration tests with Trait("Category", "Integration") and add a filter to the GitHub Actions workflow so dotnet test skips them in CI --- .github/workflows/build-ci.yml | 2 +- .../Services/ProfilerServiceUnitTests.cs | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-ci.yml b/.github/workflows/build-ci.yml index 42aee05..030bc08 100644 --- a/.github/workflows/build-ci.yml +++ b/.github/workflows/build-ci.yml @@ -21,4 +21,4 @@ jobs: - name: Build run: dotnet build --no-restore - name: Test - run: dotnet test --no-build --verbosity normal + run: dotnet test --no-build --verbosity normal --filter "Category!=Integration" diff --git a/tests/LightQueryProfiler.Shared.UnitTests/Services/ProfilerServiceUnitTests.cs b/tests/LightQueryProfiler.Shared.UnitTests/Services/ProfilerServiceUnitTests.cs index 2711d59..bf8bb60 100644 --- a/tests/LightQueryProfiler.Shared.UnitTests/Services/ProfilerServiceUnitTests.cs +++ b/tests/LightQueryProfiler.Shared.UnitTests/Services/ProfilerServiceUnitTests.cs @@ -7,6 +7,10 @@ namespace LightQueryProfiler.Shared.UnitTests.Services { + /// + /// Integration tests that require a local SQL Server instance. + /// These tests are skipped in CI environments. + /// public class ProfilerServiceUnitTests { private readonly IApplicationDbContext _applicationDbContext; @@ -27,12 +31,14 @@ public ProfilerServiceUnitTests() } [Fact] + [Trait("Category", "Integration")] public void StartProfiling() { _profilerService.StartProfiling(sessionName, _baseProfilerSessionTemplate); } [Fact] + [Trait("Category", "Integration")] public async Task GetLastEventsAsync() { List? events; @@ -47,6 +53,7 @@ public async Task GetLastEventsAsync() [Fact] + [Trait("Category", "Integration")] public void StopProfiling() { _profilerService.StopProfiling(sessionName); From 52065437164f76b7d3d9021cb8f82b9db1099c03 Mon Sep 17 00:00:00 2001 From: Hildebrando Chavez Date: Sat, 28 Feb 2026 18:04:59 -0600 Subject: [PATCH 3/4] Copy TestFiles to output and use Path.Combine Add project setting to copy TestFiles to the test output and update tests to locate sample XML via Path.Combine. Add README and docs/INTEGRATION_TESTS.md documenting test categories and requirements. --- ...LightQueryProfiler.Shared.UnitTests.csproj | 6 + .../README.md | 100 +++++++++++++++++ .../ProfilerEventUniqueKeyIntegrationTests.cs | 12 +- .../docs/INTEGRATION_TESTS.md | 105 ++++++++++++++++++ 4 files changed, 217 insertions(+), 6 deletions(-) create mode 100644 tests/LightQueryProfiler.Shared.UnitTests/README.md create mode 100644 tests/LightQueryProfiler.Shared.UnitTests/docs/INTEGRATION_TESTS.md diff --git a/tests/LightQueryProfiler.Shared.UnitTests/LightQueryProfiler.Shared.UnitTests.csproj b/tests/LightQueryProfiler.Shared.UnitTests/LightQueryProfiler.Shared.UnitTests.csproj index e89b3b4..96d8d9d 100644 --- a/tests/LightQueryProfiler.Shared.UnitTests/LightQueryProfiler.Shared.UnitTests.csproj +++ b/tests/LightQueryProfiler.Shared.UnitTests/LightQueryProfiler.Shared.UnitTests.csproj @@ -27,4 +27,10 @@ + + + PreserveNewest + + + diff --git a/tests/LightQueryProfiler.Shared.UnitTests/README.md b/tests/LightQueryProfiler.Shared.UnitTests/README.md new file mode 100644 index 0000000..2d86845 --- /dev/null +++ b/tests/LightQueryProfiler.Shared.UnitTests/README.md @@ -0,0 +1,100 @@ +# LightQueryProfiler.Shared.UnitTests + +This project contains unit and integration tests for the LightQueryProfiler.Shared library. + +## Test Structure + +``` +LightQueryProfiler.Shared.UnitTests/ +├── Enums/ # Tests for enumerations +├── Factories/ # Tests for factory classes +├── Models/ # Tests for data models +├── Services/ # Tests for service classes +├── TestFiles/ # Test data files +└── docs/ # Documentation +``` + +## Running Tests + +### All Tests (Local Development) + +```bash +dotnet test +``` + +### Unit Tests Only (CI/CD) + +```bash +dotnet test --filter "Category!=Integration" +``` + +### Integration Tests Only + +```bash +dotnet test --filter "Category=Integration" +``` + +## Test Categories + +### Unit Tests (66 tests) +- No external dependencies required +- Run automatically in CI/CD pipeline +- Fast execution + +### Integration Tests (3 tests) +- Require local SQL Server instance +- Only run locally by developers +- Marked with `[Trait("Category", "Integration")]` +- Skipped in GitHub Actions CI/CD + +## Integration Test Requirements + +Integration tests require: +- SQL Server running on `localhost` +- Windows Authentication enabled +- Permissions to create Extended Events sessions +- Access to `master` database + +For more details, see [Integration Tests Documentation](docs/INTEGRATION_TESTS.md) + +## Test Framework + +- **Framework**: xUnit v3 +- **Mocking**: Moq +- **Target Framework**: .NET 10.0 + +## CI/CD Integration + +The GitHub Actions workflow automatically excludes integration tests using: +```bash +dotnet test --no-build --verbosity normal --filter "Category!=Integration" +``` + +This ensures that CI builds don't fail due to missing SQL Server instances in the build environment. + +## Best Practices + +1. **Keep tests independent**: Each test should be able to run in isolation +2. **Use meaningful names**: Follow the pattern `MethodName_WhenCondition_ExpectedResult` +3. **Arrange-Act-Assert**: Structure tests using the AAA pattern +4. **Mark integration tests**: Use `[Trait("Category", "Integration")]` for tests requiring external resources +5. **Avoid test interdependencies**: Tests should not rely on execution order + +## Adding New Tests + +When adding new tests: + +1. Place tests in the appropriate folder based on the class being tested +2. Mirror the source code structure +3. Use `[Fact]` for single test cases +4. Use `[Theory]` with `[InlineData]` for parameterized tests +5. Add `[Trait("Category", "Integration")]` if the test requires external resources + +## Code Coverage + +To generate code coverage locally: + +```bash +dotnet tool install -g dotnet-coverage +dotnet-coverage collect -f cobertura -o coverage.cobertura.xml dotnet test +``` diff --git a/tests/LightQueryProfiler.Shared.UnitTests/Services/ProfilerEventUniqueKeyIntegrationTests.cs b/tests/LightQueryProfiler.Shared.UnitTests/Services/ProfilerEventUniqueKeyIntegrationTests.cs index 7eaf6b9..27c44a1 100644 --- a/tests/LightQueryProfiler.Shared.UnitTests/Services/ProfilerEventUniqueKeyIntegrationTests.cs +++ b/tests/LightQueryProfiler.Shared.UnitTests/Services/ProfilerEventUniqueKeyIntegrationTests.cs @@ -16,7 +16,7 @@ public ProfilerEventUniqueKeyIntegrationTests() public void ParseRealXml_AllEventsHaveUniqueKeys() { // Arrange - string sourceFile = "..\\..\\..\\TestFiles\\RingBufferTarget.xml"; + string sourceFile = Path.Combine("TestFiles", "RingBufferTarget.xml"); if (!File.Exists(sourceFile)) { Assert.Fail("Test file not found: " + sourceFile); @@ -38,7 +38,7 @@ public void ParseRealXml_AllEventsHaveUniqueKeys() public void ParseRealXml_AllEventsHaveEventSequence() { // Arrange - string sourceFile = "..\\..\\..\\TestFiles\\RingBufferTarget.xml"; + string sourceFile = Path.Combine("TestFiles", "RingBufferTarget.xml"); if (!File.Exists(sourceFile)) { Assert.Fail("Test file not found: " + sourceFile); @@ -60,7 +60,7 @@ public void ParseRealXml_AllEventsHaveEventSequence() public void ParseRealXml_EventKeysAreSequenceBased() { // Arrange - string sourceFile = "..\\..\\..\\TestFiles\\RingBufferTarget.xml"; + string sourceFile = Path.Combine("TestFiles", "RingBufferTarget.xml"); if (!File.Exists(sourceFile)) { Assert.Fail("Test file not found: " + sourceFile); @@ -81,7 +81,7 @@ public void ParseRealXml_EventKeysAreSequenceBased() public void ParseRealXml_DifferentEventTypesWithSameSequenceDoNotCollide() { // Arrange - string sourceFile = "..\\..\\..\\TestFiles\\RingBufferTarget.xml"; + string sourceFile = Path.Combine("TestFiles", "RingBufferTarget.xml"); if (!File.Exists(sourceFile)) { Assert.Fail("Test file not found: " + sourceFile); @@ -110,7 +110,7 @@ public void ParseRealXml_DifferentEventTypesWithSameSequenceDoNotCollide() public void ParseRealXml_EventSequenceValuesAreMonotonicallyIncreasing() { // Arrange - string sourceFile = "..\\..\\..\\TestFiles\\RingBufferTarget.xml"; + string sourceFile = Path.Combine("TestFiles", "RingBufferTarget.xml"); if (!File.Exists(sourceFile)) { Assert.Fail("Test file not found: " + sourceFile); @@ -137,7 +137,7 @@ public void ParseRealXml_EventSequenceValuesAreMonotonicallyIncreasing() public void ParseRealXml_EventKeysMatchExpectedFormat() { // Arrange - string sourceFile = "..\\..\\..\\TestFiles\\RingBufferTarget.xml"; + string sourceFile = Path.Combine("TestFiles", "RingBufferTarget.xml"); if (!File.Exists(sourceFile)) { Assert.Fail("Test file not found: " + sourceFile); diff --git a/tests/LightQueryProfiler.Shared.UnitTests/docs/INTEGRATION_TESTS.md b/tests/LightQueryProfiler.Shared.UnitTests/docs/INTEGRATION_TESTS.md new file mode 100644 index 0000000..a27043c --- /dev/null +++ b/tests/LightQueryProfiler.Shared.UnitTests/docs/INTEGRATION_TESTS.md @@ -0,0 +1,105 @@ +# Integration Tests Documentation + +## Overview + +This project contains both unit tests and integration tests. Integration tests require a local SQL Server instance and are marked with the `[Trait("Category", "Integration")]` attribute. + +## Test Categories + +### Unit Tests +- **Location**: All test files in `LightQueryProfiler.Shared.UnitTests` +- **Requirements**: No external dependencies +- **Execution**: Run automatically in CI/CD pipelines + +### Integration Tests +- **Location**: `Services/ProfilerServiceUnitTests.cs` +- **Requirements**: Local SQL Server instance running on `localhost` +- **Execution**: Only run locally by developers + +## Running Tests + +### Running All Tests (Local Development) + +To run all tests including integration tests: + +```bash +dotnet test +``` + +### Running Only Unit Tests (CI/CD) + +To run only unit tests (excluding integration tests): + +```bash +dotnet test --filter "Category!=Integration" +``` + +This is the default behavior in the GitHub Actions CI/CD pipeline. + +### Running Only Integration Tests + +To run only integration tests: + +```bash +dotnet test --filter "Category=Integration" +``` + +## Integration Test Requirements + +The integration tests in `ProfilerServiceUnitTests.cs` require: + +1. **SQL Server**: A local SQL Server instance accessible at `localhost` +2. **Connection String**: `Server=localhost;Database=master;Trusted_Connection=True;TrustServerCertificate=True;` +3. **Permissions**: The Windows user running the tests must have permissions to: + - Create and manage Extended Events sessions + - Access the `master` database + +## CI/CD Behavior + +The GitHub Actions workflow (`.github/workflows/build-ci.yml`) automatically excludes integration tests using the filter `--filter "Category!=Integration"`. This prevents CI builds from failing due to missing SQL Server instances in the GitHub-hosted runners. + +## Adding New Integration Tests + +When adding new tests that require database connectivity or other external resources: + +1. Add the `[Trait("Category", "Integration")]` attribute to the test method +2. Document any specific requirements in this file +3. Ensure the test can be skipped without breaking the CI/CD pipeline + +### Example + +```csharp +[Fact] +[Trait("Category", "Integration")] +public async Task MyNewTest_RequiresDatabase() +{ + // Test implementation that requires SQL Server +} +``` + +## Troubleshooting + +### Integration Tests Fail Locally + +If integration tests fail on your local machine: + +1. Verify SQL Server is running: `sqlcmd -S localhost -E -Q "SELECT @@VERSION"` +2. Check Windows Authentication is enabled +3. Verify your user has necessary permissions +4. Check the connection string in `ProfilerServiceUnitTests.cs` + +### Tests Run Slowly + +Integration tests are slower than unit tests because they: +- Connect to a real database +- Create and manage Extended Events sessions +- Process real event data + +This is expected behavior. + +## Best Practices + +1. **Keep integration tests separate**: Don't mix database operations in unit tests +2. **Use traits consistently**: Always use `[Trait("Category", "Integration")]` for tests requiring external resources +3. **Document dependencies**: Update this file when adding new integration test requirements +4. **Local testing**: Run integration tests locally before committing changes to database-related code \ No newline at end of file From 9b6c0131d8368ba4163746437716944eceb081eb Mon Sep 17 00:00:00 2001 From: Hildebrando Chavez Date: Sat, 28 Feb 2026 18:12:52 -0600 Subject: [PATCH 4/4] Use Path.Combine for test file path --- .../Services/XEventServiceUnitTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/LightQueryProfiler.Shared.UnitTests/Services/XEventServiceUnitTests.cs b/tests/LightQueryProfiler.Shared.UnitTests/Services/XEventServiceUnitTests.cs index a47c998..4a8579a 100644 --- a/tests/LightQueryProfiler.Shared.UnitTests/Services/XEventServiceUnitTests.cs +++ b/tests/LightQueryProfiler.Shared.UnitTests/Services/XEventServiceUnitTests.cs @@ -15,7 +15,7 @@ public XEventServiceUnitTests() [Fact] public void Parse() { - string sourceFile = "..\\..\\..\\TestFiles\\RingBufferTarget.xml"; + string sourceFile = Path.Combine("TestFiles", "RingBufferTarget.xml"); if (File.Exists(sourceFile) == false) { throw new Exception("File not found");