# Test Performance Optimization **Last Updated:** 2026-01-28 **Status:** ✅ Active optimization program --- ## Executive Summary This document provides a comprehensive overview of test performance optimizations, risk assessments, and future opportunities. The test suite execution time has been reduced through systematic analysis and targeted optimizations. ### Current Performance Metrics | Metric | Value | |--------|-------| | **Total Execution Time** (without `:slow` tests) | ~368 seconds (~6.1 minutes) | | **Total Tests** | 1,336 tests (+ 25 doctests) | | **Async Execution** | 163.5 seconds | | **Sync Execution** | 281.5 seconds | | **Slow Tests Excluded** | 25 tests (tagged with `@tag :slow`) | | **Top 50 Slowest Tests** | 121.9 seconds (27.4% of total time) | ### Optimization Impact Summary | Optimization | Tests Affected | Time Saved | Status | |--------------|----------------|------------|--------| | Seeds tests reduction | 13 → 4 tests | ~10-16s | ✅ Completed | | Performance tests tagging | 9 tests | ~3-4s per run | ✅ Completed | | Critical test query filtering | 1 test | ~8-10s | ✅ Completed | | Full test suite via promotion | 25 tests | ~77s per run | ✅ Completed | | **Total Saved** | | **~98-107s** | | --- ## Completed Optimizations ### 1. Seeds Test Suite Optimization **Date:** 2026-01-28 **Status:** ✅ Completed #### What Changed - **Reduced test count:** From 13 tests to 4 tests (69% reduction) - **Reduced seeds executions:** From 8-10 times to 5 times per test run - **Execution time:** From 24-30 seconds to 13-17 seconds - **Time saved:** ~10-16 seconds per test run (40-50% faster) #### Removed Tests (9 tests) Tests were removed because their functionality is covered by domain-specific test suites: 1. `"at least one member has no membership fee type assigned"` → Covered by `membership_fees/*_test.exs` 2. `"each membership fee type has at least one member"` → Covered by `membership_fees/*_test.exs` 3. `"members with fee types have cycles with various statuses"` → Covered by `cycle_generator_test.exs` 4. `"creates all 5 authorization roles with correct permission sets"` → Covered by `authorization/*_test.exs` 5. `"all roles have valid permission_set_names"` → Covered by `authorization/permission_sets_test.exs` 6. `"does not change role of users who already have a role"` → Merged into idempotency test 7. `"role creation is idempotent"` (detailed) → Merged into general idempotency test #### Retained Tests (4 tests) Critical deployment requirements are still covered: 1. ✅ **Smoke Test:** Seeds run successfully and create basic data 2. ✅ **Idempotency Test:** Seeds can be run multiple times without duplicating data 3. ✅ **Admin Bootstrap:** Admin user exists with Admin role (critical for initial access) 4. ✅ **System Role Bootstrap:** Mitglied system role exists (critical for user registration) #### Risk Assessment | Removed Test Category | Alternative Coverage | Risk Level | |----------------------|---------------------|------------| | Member/fee type distribution | `membership_fees/*_test.exs` | ⚠️ Low | | Cycle status variations | `cycle_generator_test.exs` | ⚠️ Low | | Detailed role configs | `authorization/*_test.exs` | ⚠️ Very Low | | Permission set validation | `permission_sets_test.exs` | ⚠️ Very Low | **Overall Risk:** ⚠️ **Low** - All removed tests have equivalent or better coverage in domain-specific test suites. --- ### 2. Full Test Suite via Promotion (`@tag :slow`) **Date:** 2026-01-28 **Status:** ✅ Completed #### What Changed Tests with **low risk** and **execution time >1 second** are now tagged with `@tag :slow` and excluded from standard test runs. These tests are important but not critical for every commit and are run via promotion before merging to `main`. #### Tagging Criteria **Tagged as `@tag :slow` when:** - ✅ Test execution time >1 second - ✅ Low risk (not critical for catching regressions in core business logic) - ✅ UI/Display tests (formatting, rendering) - ✅ Workflow detail tests (not core functionality) - ✅ Edge cases with large datasets **NOT tagged when:** - ❌ Core CRUD operations (Member/User Create/Update/Destroy) - ❌ Basic Authentication/Authorization - ❌ Critical Bootstrap (Admin user, system roles) - ❌ Email Synchronization - ❌ Representative tests per Permission Set + Action #### Identified Tests for Full Test Suite (25 tests) **1. Seeds Tests (2 tests) - 18.1s** - `"runs successfully and creates basic data"` (9.0s) - `"is idempotent when run multiple times"` (9.1s) - **Note:** Critical bootstrap tests remain in fast suite **2. UserLive.ShowTest (3 tests) - 10.8s** - `"mounts successfully with valid user ID"` (4.2s) - `"displays linked member when present"` (2.4s) - `"redirects to user list when viewing system actor user"` (4.2s) **3. UserLive.IndexTest (5 tests) - 25.0s** - `"displays users in a table"` (1.0s) - `"initially sorts by email ascending"` (2.2s) - `"can sort email descending by clicking sort button"` (3.4s) - `"select all automatically checks when all individual users are selected"` (2.0s) - `"displays linked member name in user list"` (1.9s) **4. MemberLive.IndexCustomFieldsDisplayTest (3 tests) - 4.9s** - `"displays custom field with show_in_overview: true"` (1.6s) - `"formats date custom field values correctly"` (1.5s) - `"formats email custom field values correctly"` (1.8s) **5. MemberLive.IndexCustomFieldsEdgeCasesTest (3 tests) - 3.6s** - `"displays custom field column even when no members have values"` (1.1s) - `"displays very long custom field values correctly"` (1.4s) - `"handles multiple custom fields with show_in_overview correctly"` (1.2s) **6. RoleLive Tests (7 tests) - 7.7s** - `role_live_test.exs`: `"mounts successfully"` (1.5s), `"deletes non-system role"` (2.1s) - `role_live/show_test.exs`: 5 tests >1s (mount, display, navigation) **7. MemberAvailableForLinkingTest (1 test) - 1.5s** - `"limits results to 10 members even when more exist"` (1.5s) **8. Performance Tests (1 test) - 3.8s** - `"boolean filter performance with 150 members"` (3.8s) **Total:** 25 tests, ~77 seconds saved #### Execution Commands **Fast Tests (Default):** ```bash just test-fast # or mix test --exclude slow ``` **Slow Tests Only:** ```bash just test-slow # or mix test --only slow ``` **All Tests:** ```bash just test # or mix test ``` #### CI/CD Integration - **Standard CI (`check-fast`):** Runs `mix test --exclude slow --exclude ui` for faster feedback loops (~6 minutes) - **Full Test Suite (`check-full`):** Triggered via promotion before merge, executes `mix test` (all tests, including slow and UI) for comprehensive coverage (~7.4 minutes) - **Pre-Merge:** Full test suite (`mix test`) runs via promotion before merging to main - **Manual Execution:** Promote build to `production` in Drone CI to trigger full test suite #### Risk Assessment **Risk Level:** ✅ **Very Low** - All tagged tests have **low risk** - they don't catch critical regressions - Core functionality remains tested (CRUD, Auth, Bootstrap) - Standard test runs are faster (~6 minutes vs ~7.4 minutes) - Full test suite runs via promotion before merge ensures comprehensive coverage - No functionality is lost, only execution timing changed **Critical Tests Remain in Fast Suite:** - Core CRUD operations (Member/User Create/Update/Destroy) - Basic Authentication/Authorization - Critical Bootstrap (Admin user, system roles) - Email Synchronization - Representative Policy tests (one per Permission Set + Action) --- ### 3. Critical Test Optimization **Date:** 2026-01-28 **Status:** ✅ Completed #### Problem Identified The test `test respects show_in_overview config` was the slowest test in the suite: - **Isolated execution:** 4.8 seconds - **In full test run:** 14.7 seconds - **Difference:** 9.9 seconds (test isolation issue) #### Root Cause The test loaded **all members** from the database, not just the 2 members from the test setup. In full test runs, many members from other tests were present in the database, significantly slowing down the query. #### Solution Implemented **Query Filtering:** Added search query parameter to filter to only the expected member. **Code Change:** ```elixir # Before: {:ok, _view, html} = live(conn, "/members") # After: {:ok, _view, html} = live(conn, "/members?query=Alice") ``` #### Results | Execution | Before | After | Improvement | |-----------|--------|-------|-------------| | **Isolated** | 4.8s | 1.1s | **-77%** (3.7s saved) | | **In Module** | 4.2s | 0.4s | **-90%** (3.8s saved) | | **Expected in Full Run** | 14.7s | ~4-6s | **-65% to -73%** (8-10s saved) | #### Risk Assessment **Risk Level:** ✅ **Very Low** - Test functionality unchanged - only loads expected data - All assertions still pass - Test is now faster and more isolated - No impact on test coverage --- ### 3. Full Test Suite Analysis and Categorization **Date:** 2026-01-28 **Status:** ✅ Completed #### Analysis Methodology A comprehensive analysis was performed to identify tests suitable for the full test suite (via promotion) based on: - **Execution time:** Tests taking >1 second - **Risk assessment:** Tests that don't catch critical regressions - **Test category:** UI/Display, workflow details, edge cases #### Test Categorization **🔴 CRITICAL - Must Stay in Fast Suite:** - Core Business Logic (Member/User CRUD) - Authentication & Authorization Basics - Critical Bootstrap (Admin user, system roles) - Email Synchronization - Representative Policy Tests (one per Permission Set + Action) **🟡 LOW RISK - Moved to Full Test Suite (via Promotion):** - Seeds Tests (non-critical: smoke test, idempotency) - LiveView Display/Formatting Tests - UserLive.ShowTest (core functionality covered by Index/Form) - UserLive.IndexTest UI Features (sorting, checkboxes, navigation) - RoleLive Tests (role management, not core authorization) - MemberLive Custom Fields Display Tests - Edge Cases with Large Datasets #### Risk Assessment Summary | Category | Tests | Time Saved | Risk Level | Rationale | |----------|-------|------------|------------|-----------| | Seeds (non-critical) | 2 | 18.1s | ⚠️ Low | Critical bootstrap tests remain | | UserLive.ShowTest | 3 | 10.8s | ⚠️ Low | Core CRUD covered by Index/Form | | UserLive.IndexTest (UI) | 5 | 25.0s | ⚠️ Low | UI features, not core functionality | | Custom Fields Display | 6 | 8.5s | ⚠️ Low | Formatting tests, visible in code review | | RoleLive Tests | 7 | 7.7s | ⚠️ Low | Role management, not authorization | | Edge Cases | 1 | 1.5s | ⚠️ Low | Edge case, not critical path | | Performance Tests | 1 | 3.8s | ✅ Very Low | Explicit performance validation | | **Total** | **25** | **~77s** | **⚠️ Low** | | **Overall Risk:** ⚠️ **Low** - All moved tests have low risk and don't catch critical regressions. Core functionality remains fully tested. #### Tests Excluded from Full Test Suite The following tests were **NOT** moved to full test suite (via promotion) despite being slow: - **Policy Tests:** Medium risk - kept in fast suite (representative tests remain) - **UserLive.FormTest:** Medium risk - core CRUD functionality - **Tests <1s:** Don't meet execution time threshold - **Critical Bootstrap Tests:** High risk - deployment critical --- ## Current Performance Analysis ### Top 20 Slowest Tests (without `:slow`) After implementing the full test suite via promotion, the remaining slowest tests are: | Rank | Test | File | Time | Category | |------|------|------|------|----------| | 1 | `test Critical bootstrap invariants Mitglied system role exists` | `seeds_test.exs` | 6.7s | Critical Bootstrap | | 2 | `test Critical bootstrap invariants Admin user has Admin role` | `seeds_test.exs` | 5.0s | Critical Bootstrap | | 3 | `test normal_user permission set can read own user record` | `user_policies_test.exs` | 2.6s | Policy Test | | 4 | `test normal_user permission set can create member` | `member_policies_test.exs` | 2.5s | Policy Test | | 5-20 | Various Policy and LiveView tests | Multiple files | 1.5-2.4s each | Policy/LiveView | **Total Top 20:** ~44 seconds (12% of total time without `:slow`) **Note:** Many previously slow tests (UserLive.IndexTest, UserLive.ShowTest, Display/Formatting tests) are now tagged with `@tag :slow` and excluded from standard runs. ### Performance Hotspots Identified #### 1. Seeds Tests (~16.2s for 4 tests) **Status:** ✅ Optimized (reduced from 13 tests) **Remaining Optimization Potential:** 3-5 seconds **Opportunities:** - Settings update could potentially be moved to `setup_all` (if sandbox allows) - Seeds execution could be further optimized (less data in test mode) - Idempotency test could be optimized (only 1x seeds instead of 2x) #### 2. User LiveView Tests (~35.5s for 10 tests) **Status:** ⏳ Identified for optimization **Optimization Potential:** 15-20 seconds **Files:** - `test/mv_web/user_live/index_test.exs` (3 tests, ~10.2s) - `test/mv_web/user_live/form_test.exs` (4 tests, ~15.0s) - `test/mv_web/user_live/show_test.exs` (3 tests, ~10.3s) **Patterns:** - Many tests create user/member data - LiveView mounts are expensive - Form submissions with validations are slow **Recommended Actions:** - Move shared fixtures to `setup_all` - Reduce test data volume (3-5 users instead of 10+) - Optimize setup patterns for recurring patterns #### 3. Policy Tests (~8.7s for 3 tests) **Status:** ⏳ Identified for optimization **Optimization Potential:** 5-8 seconds **Files:** - `test/mv/membership/member_policies_test.exs` (2 tests, ~6.1s) - `test/mv/accounts/user_policies_test.exs` (1 test, ~2.6s) **Pattern:** - Each test creates new roles/users/members - Roles are identical across tests **Recommended Actions:** - Create roles in `setup_all` (shared across tests) - Reuse common fixtures - Maintain test isolation while optimizing setup --- ## Future Optimization Opportunities ### Priority 1: User LiveView Tests Optimization **Estimated Savings:** 14-22 seconds **Status:** 📋 Analysis Complete - Ready for Implementation #### Analysis Summary Analysis of User LiveView tests identified significant optimization opportunities: - **Framework functionality over-testing:** ~30 tests test Phoenix/Ash/Gettext core features - **Redundant test data creation:** Each test creates users/members independently - **Missing shared fixtures:** No `setup_all` usage for common data #### Current Performance **Top 20 Slowest Tests (User LiveView):** - `index_test.exs`: ~10.2s for 3 tests in Top 20 - `form_test.exs`: ~15.0s for 4 tests in Top 20 - `show_test.exs`: ~10.3s for 3 tests in Top 20 - **Total:** ~35.5 seconds for User LiveView tests #### Optimization Opportunities **1. Remove Framework Functionality Tests (~30 tests, 8-12s saved)** - Remove translation tests (Gettext framework) - Remove navigation tests (Phoenix LiveView framework) - Remove validation tests (Ash framework) - Remove basic HTML rendering tests (consolidate into smoke test) - Remove password storage tests (AshAuthentication framework) **2. Implement Shared Fixtures (3-5s saved)** - Use `setup_all` for common test data in `index_test.exs` and `show_test.exs` - Share users for sorting/checkbox tests - Share common users/members across tests - **Note:** `form_test.exs` uses `async: false`, preventing `setup_all` usage **3. Consolidate Redundant Tests (~10 tests → 3-4 tests, 2-3s saved)** - Merge basic display tests into smoke test - Merge navigation tests into integration test - Reduce sorting tests to 1 integration test **4. Optimize Test Data Volume (1-2s saved)** - Use minimum required data (2 users for sorting, 2 for checkboxes) - Share data across tests via `setup_all` #### Tests to Keep (Business Logic) **Index Tests:** - `initially sorts by email ascending` - Tests default sort - `can sort email descending by clicking sort button` - Tests sort functionality - `select all automatically checks when all individual users are selected` - Business logic - `does not show system actor user in list` - Business rule - `displays linked member name in user list` - Business logic - Edge case tests **Form Tests:** - `creates user without password` - Business logic - `creates user with password when enabled` - Business logic - `admin sets new password for user` - Business logic - `selecting member and saving links member to user` - Business logic - Member linking/unlinking workflow tests **Show Tests:** - `displays password authentication status` - Business logic - `displays linked member when present` - Business logic - `redirects to user list when viewing system actor user` - Business rule #### Implementation Plan **Phase 1: Remove Framework Tests (1-2 hours, ⚠️ Very Low Risk)** - Remove translation, navigation, validation, and basic HTML rendering tests - Consolidate remaining display tests into smoke test **Phase 2: Implement Shared Fixtures (2-3 hours, ⚠️ Low Risk)** - Add `setup_all` to `index_test.exs` and `show_test.exs` - Update tests to use shared fixtures - Verify test isolation maintained **Phase 3: Consolidate Tests (1-2 hours, ⚠️ Very Low Risk)** - Merge basic display tests into smoke test - Merge navigation tests into integration test - Reduce sorting tests to 1 integration test **Risk Assessment:** ⚠️ **Low** - Framework functionality is tested by framework maintainers - Business logic tests remain intact - Shared fixtures maintain test isolation - Consolidation preserves coverage ### Priority 2: Policy Tests Optimization **Estimated Savings:** 5.5-9 seconds **Status:** 📋 Analysis Complete - Ready for Decision #### Analysis Summary Analysis of policy tests identified significant optimization opportunities: - **Redundant fixture creation:** Roles and users created repeatedly across tests - **Framework functionality over-testing:** Many tests verify Ash policy framework behavior - **Test duplication:** Similar tests across different permission sets #### Current Performance **Policy Test Files Performance:** - `member_policies_test.exs`: 24 tests, ~66s (top 20) - `user_policies_test.exs`: 30 tests, ~66s (top 20) - `custom_field_value_policies_test.exs`: 20 tests, ~66s (top 20) - **Total:** 74 tests, ~152s total **Top 20 Slowest Policy Tests:** ~66 seconds #### Framework vs. Business Logic Analysis **Framework Functionality (Should NOT Test):** - Policy evaluation (how Ash evaluates policies) - Permission lookup (how Ash looks up permissions) - Scope filtering (how Ash applies scope filters) - Auto-filter behavior (how Ash auto-filters queries) - Forbidden vs NotFound (how Ash returns errors) **Business Logic (Should Test):** - Permission set definitions (what permissions each role has) - Scope definitions (what scopes each permission set uses) - Special cases (custom business rules) - Permission set behavior (how our permission sets differ) #### Optimization Opportunities **1. Remove Framework Functionality Tests (~22-34 tests, 3-4s saved)** - Remove "cannot" tests that verify error types (Forbidden, NotFound) - Remove tests that verify auto-filter behavior (framework) - Remove tests that verify permission evaluation (framework) - **Risk:** ⚠️ Very Low - Framework functionality is tested by Ash maintainers **2. Consolidate Redundant Tests (~6-8 tests → 2-3 tests, 1-2s saved)** - Merge similar tests across permission sets - Create integration tests that cover multiple permission sets - **Risk:** ⚠️ Low - Same coverage, fewer tests **3. Share Admin User Across Describe Blocks (1-2s saved)** - Create admin user once in module-level `setup` - Reuse admin user in helper functions - **Note:** `async: false` prevents `setup_all`, but module-level `setup` works - **Risk:** ⚠️ Low - Admin user is read-only in tests, safe to share **4. Reduce Test Data Volume (0.5-1s saved)** - Use minimum required data - Share fixtures where possible - **Risk:** ⚠️ Very Low - Still tests same functionality #### Test Classification Summary **Tests to Remove (Framework):** - `member_policies_test.exs`: ~10 tests (cannot create/destroy/update, auto-filter tests) - `user_policies_test.exs`: ~16 tests (cannot read/update/create/destroy, auto-filter tests) - `custom_field_value_policies_test.exs`: ~8 tests (similar "cannot" tests) **Tests to Consolidate (Redundant):** - `user_policies_test.exs`: 6 tests → 2 tests (can read/update own user record) **Tests to Keep (Business Logic):** - All "can" tests that verify permission set behavior - Special case tests (e.g., "user can always READ linked member") - AshAuthentication bypass tests (our integration) #### Implementation Plan **Phase 1: Remove Framework Tests (1-2 hours, ⚠️ Very Low Risk)** - Identify all "cannot" tests that verify error types - Remove tests that verify Ash auto-filter behavior - Remove tests that verify permission evaluation (framework) **Phase 2: Consolidate Redundant Tests (1-2 hours, ⚠️ Low Risk)** - Identify similar tests across permission sets - Create integration tests that cover multiple permission sets - Remove redundant individual tests **Phase 3: Share Admin User (1-2 hours, ⚠️ Low Risk)** - Add module-level `setup` to create admin user - Update helper functions to accept admin user parameter - Update all `setup` blocks to use shared admin user **Risk Assessment:** ⚠️ **Low** - Framework functionality is tested by Ash maintainers - Business logic tests remain intact - Admin user sharing maintains test isolation (read-only) - Consolidation preserves coverage ### Priority 3: Seeds Tests Further Optimization **Estimated Savings:** 3-5 seconds **Actions:** 1. Investigate if settings update can be moved to `setup_all` 2. Introduce seeds mode for tests (less data in test mode) 3. Optimize idempotency test (only 1x seeds instead of 2x) **Risk Assessment:** ⚠️ **Low to Medium** - Sandbox limitations may prevent `setup_all` usage - Seeds mode would require careful implementation - Idempotency test optimization needs to maintain test validity ### Priority 4: Additional Test Isolation Improvements **Estimated Savings:** Variable (depends on specific tests) **Actions:** 1. Review tests that load all records (similar to the critical test fix) 2. Add query filters where appropriate 3. Ensure proper test isolation in async tests **Risk Assessment:** ⚠️ **Very Low** - Similar to the critical test optimization (proven approach) - Improves test isolation and reliability --- ## Estimated Total Optimization Potential | Priority | Optimization | Estimated Savings | |----------|-------------|-------------------| | 1 | User LiveView Tests | 14-22s | | 2 | Policy Tests | 5.5-9s | | 3 | Seeds Tests Further | 3-5s | | 4 | Additional Isolation | Variable | | **Total Potential** | | **22.5-36 seconds** | **Projected Final Time:** From ~368 seconds (fast suite) to **~332-345 seconds** (~5.5-5.8 minutes) with remaining optimizations **Note:** Detailed analysis documents available: - User LiveView Tests: See "Priority 1: User LiveView Tests Optimization" section above - Policy Tests: See "Priority 2: Policy Tests Optimization" section above --- ## Risk Assessment Summary ### Overall Risk Level: ⚠️ **Low** All optimizations maintain test coverage while improving performance: | Optimization | Risk Level | Mitigation | |-------------|------------|------------| | Seeds tests reduction | ⚠️ Low | Coverage mapped to domain tests | | Performance tests tagging | ✅ Very Low | Tests still executed, just separately | | Critical test optimization | ✅ Very Low | Functionality unchanged, better isolation | | Future optimizations | ⚠️ Low | Careful implementation with verification | ### Monitoring Plan #### Success Criteria - ✅ Seeds tests execute in <20 seconds consistently - ✅ No increase in seeds-related deployment failures - ✅ No regression in authorization or membership fee bugs - ✅ Top 20 slowest tests: < 60 seconds (currently ~44s) - ✅ Total execution time (without `:slow`): < 10 minutes (currently 6.1 min) - ⏳ Slow tests execution time: < 2 minutes (currently ~1.3 min) #### What to Watch For 1. **Production Seeds Failures:** - Monitor deployment logs for seeds errors - If failures increase, consider restoring detailed tests 2. **Authorization Bugs After Seeds Changes:** - If role/permission bugs appear after seeds modifications - May indicate need for more seeds-specific role validation 3. **Test Performance Regression:** - Monitor test execution times in CI - Alert if times increase significantly 4. **Developer Feedback:** - If developers report missing test coverage - Adjust based on real-world experience --- ## Benchmarking and Analysis ### How to Benchmark Tests **ExUnit Built-in Benchmarking:** The test suite is configured to show the slowest tests automatically: ```elixir # test/test_helper.exs ExUnit.start( slowest: 10 # Shows 10 slowest tests at the end of test run ) ``` **Run Benchmark Analysis:** ```bash # Show slowest tests mix test --slowest 20 # Exclude slow tests for faster feedback mix test --exclude slow --slowest 20 # Run only slow tests mix test --only slow --slowest 10 # Benchmark specific test file mix test test/mv_web/member_live/index_member_fields_display_test.exs --slowest 5 ``` ### Benchmarking Best Practices 1. **Run benchmarks regularly** (e.g., monthly) to catch performance regressions 2. **Compare isolated vs. full runs** to identify test isolation issues 3. **Monitor CI execution times** to track trends over time 4. **Document significant changes** in test performance --- ## Test Suite Structure ### Test Execution Modes **Fast Tests (Default):** - Excludes slow tests (`@tag :slow`) - Used for standard development workflow - Execution time: ~6 minutes - Command: `mix test --exclude slow` or `just test-fast` **Slow Tests:** - Tests tagged with `@tag :slow` or `@describetag :slow` (25 tests) - Low risk, >1 second execution time - UI/Display tests, workflow details, edge cases, performance tests - Execution time: ~1.3 minutes - Command: `mix test --only slow` or `just test-slow` - Excluded from standard CI runs **Full Test Suite (via Promotion):** - Triggered by promoting a build to `production` in Drone CI - Runs all tests (`mix test`) for comprehensive coverage - Execution time: ~7.4 minutes - Required before merging to `main` (enforced via branch protection) **All Tests:** - Includes both fast and slow tests - Used for comprehensive validation (pre-merge) - Execution time: ~7.4 minutes - Command: `mix test` or `just test` ### Test Organization Tests are organized to mirror the `lib/` directory structure: ``` test/ ├── accounts/ # Accounts domain tests ├── membership/ # Membership domain tests ├── membership_fees/ # Membership fees domain tests ├── mv/ # Core application tests │ ├── accounts/ # User-related tests │ ├── membership/ # Member-related tests │ └── authorization/ # Authorization tests ├── mv_web/ # Web layer tests │ ├── controllers/ # Controller tests │ ├── live/ # LiveView tests │ └── components/ # Component tests └── support/ # Test helpers ├── conn_case.ex # Controller test setup └── data_case.ex # Database test setup ``` --- ## Best Practices for Test Performance ### When Writing New Tests 1. **Use `async: true`** when possible (for parallel execution) 2. **Filter queries** to only load necessary data 3. **Share fixtures** in `setup_all` when appropriate 4. **Tag performance tests** with `@tag :slow` if they use large datasets 5. **Keep test data minimal** - only create what's needed for the test ### When Optimizing Existing Tests 1. **Measure first** - Use `mix test --slowest` to identify bottlenecks 2. **Compare isolated vs. full runs** - Identify test isolation issues 3. **Optimize setup** - Move shared data to `setup_all` where possible 4. **Filter queries** - Only load data needed for the test 5. **Verify coverage** - Ensure optimizations don't reduce test coverage ### Test Tagging Guidelines #### Tag as `@tag :slow` when: 1. **Performance Tests:** - Explicitly testing performance characteristics - Using large datasets (50+ records) - Testing scalability or query optimization - Validating N+1 query prevention 2. **Low-Risk Tests (>1s):** - UI/Display/Formatting tests (not critical for every commit) - Workflow detail tests (not core functionality) - Edge cases with large datasets - Show page tests (core functionality covered by Index/Form tests) - Non-critical seeds tests (smoke tests, idempotency) #### Do NOT tag as `@tag :slow` when: - ❌ Test is slow due to inefficient setup (fix the setup instead) - ❌ Test is slow due to bugs (fix the bug instead) - ❌ Core CRUD operations (Member/User Create/Update/Destroy) - ❌ Basic Authentication/Authorization - ❌ Critical Bootstrap (Admin user, system roles) - ❌ Email Synchronization - ❌ Representative Policy tests (one per Permission Set + Action) - ❌ It's an integration test (use `@tag :integration` instead) --- ## Changelog ### 2026-01-28: Initial Optimization Phase **Completed:** - ✅ Reduced seeds tests from 13 to 4 tests - ✅ Tagged 9 performance tests with `@tag :slow` - ✅ Optimized critical test with query filtering - ✅ Created slow test suite infrastructure - ✅ Updated CI/CD to exclude slow tests from standard runs - ✅ Added promotion-based full test suite pipeline (`check-full`) **Time Saved:** ~21-30 seconds per test run ### 2026-01-28: Full Test Suite via Promotion Implementation **Completed:** - ✅ Analyzed all tests for full test suite candidates - ✅ Identified 36 tests with low risk and >1s execution time - ✅ Tagged 25 tests with `@tag :slow` for full test suite (via promotion) - ✅ Categorized tests by risk level and execution time - ✅ Documented tagging criteria and guidelines **Tests Tagged:** - 2 Seeds tests (non-critical) - 18.1s - 3 UserLive.ShowTest tests - 10.8s - 5 UserLive.IndexTest tests - 25.0s - 3 MemberLive.IndexCustomFieldsDisplayTest tests - 4.9s - 3 MemberLive.IndexCustomFieldsEdgeCasesTest tests - 3.6s - 7 RoleLive tests - 7.7s - 1 MemberAvailableForLinkingTest - 1.5s - 1 Performance test (already tagged) - 3.8s **Time Saved:** ~77 seconds per test run **Total Optimization Impact:** - **Before:** ~445 seconds (7.4 minutes) - **After (fast suite):** ~368 seconds (6.1 minutes) - **Time saved:** ~77 seconds (17% reduction) **Next Steps:** - ⏳ Monitor full test suite execution via promotion in CI - ⏳ Optimize remaining slow tests (Policy tests, etc.) - ⏳ Further optimize Seeds tests (Priority 3) --- ## References - **Testing Standards:** `CODE_GUIDELINES.md` - Section 4 (Testing Standards) - **CI/CD Configuration:** `.drone.yml` - **Test Helper:** `test/test_helper.exs` - **Justfile Commands:** `Justfile` (test-fast, test-slow, test-all) --- ## Questions & Answers **Q: What if seeds create wrong data and break the system?** A: The smoke test will fail if seeds raise errors. Domain tests ensure business logic is correct regardless of seeds content. **Q: What if we add a new critical bootstrap requirement?** A: Add a new test to the "Critical bootstrap invariants" section in `test/seeds_test.exs`. **Q: How do we know the removed tests aren't needed?** A: Monitor for 2-3 months. If no seeds-related bugs appear that would have been caught by removed tests, they were redundant. **Q: Should we restore the tests for important releases?** A: Consider running the full test suite (including slow tests) before major releases. Daily development uses the optimized suite. **Q: How do I add a new performance test?** A: Tag it with `@tag :slow` for individual tests or `@describetag :slow` for describe blocks. Use `@describetag` instead of `@moduletag` to avoid tagging unrelated tests. Include measurable performance assertions (query counts, timing with tolerance, etc.). See "Performance Test Guidelines" section above. **Q: Can I run slow tests locally?** A: Yes, use `just test-slow` or `mix test --only slow`. They're excluded from standard runs for faster feedback. **Q: What is the "full test suite"?** A: The full test suite runs **all tests** (`mix test`), including slow and UI tests. Tests tagged with `@tag :slow` or `@describetag :slow` are excluded from standard CI runs (`check-fast`) for faster feedback, but are included when promoting a build to `production` (`check-full`) before merging to `main`. **Q: Which tests should I tag as `:slow`?** A: Tag tests with `@tag :slow` if they: (1) take >1 second, (2) have low risk (not critical for catching regressions), and (3) test UI/Display/Formatting or workflow details. See "Test Tagging Guidelines" section for details. **Q: What if a slow test fails in the full test suite?** A: If a test in the full test suite fails, investigate the failure. If it indicates a critical regression, consider moving it back to the fast suite. If it's a flaky test, fix the test itself. The merge will be blocked until all tests pass.