fraiseql-confiture 0.3.4__cp311-cp311-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. confiture/__init__.py +48 -0
  2. confiture/_core.cp311-win_amd64.pyd +0 -0
  3. confiture/cli/__init__.py +0 -0
  4. confiture/cli/dry_run.py +116 -0
  5. confiture/cli/lint_formatter.py +193 -0
  6. confiture/cli/main.py +1656 -0
  7. confiture/config/__init__.py +0 -0
  8. confiture/config/environment.py +263 -0
  9. confiture/core/__init__.py +51 -0
  10. confiture/core/anonymization/__init__.py +0 -0
  11. confiture/core/anonymization/audit.py +485 -0
  12. confiture/core/anonymization/benchmarking.py +372 -0
  13. confiture/core/anonymization/breach_notification.py +652 -0
  14. confiture/core/anonymization/compliance.py +617 -0
  15. confiture/core/anonymization/composer.py +298 -0
  16. confiture/core/anonymization/data_subject_rights.py +669 -0
  17. confiture/core/anonymization/factory.py +319 -0
  18. confiture/core/anonymization/governance.py +737 -0
  19. confiture/core/anonymization/performance.py +1092 -0
  20. confiture/core/anonymization/profile.py +284 -0
  21. confiture/core/anonymization/registry.py +195 -0
  22. confiture/core/anonymization/security/kms_manager.py +547 -0
  23. confiture/core/anonymization/security/lineage.py +888 -0
  24. confiture/core/anonymization/security/token_store.py +686 -0
  25. confiture/core/anonymization/strategies/__init__.py +41 -0
  26. confiture/core/anonymization/strategies/address.py +359 -0
  27. confiture/core/anonymization/strategies/credit_card.py +374 -0
  28. confiture/core/anonymization/strategies/custom.py +161 -0
  29. confiture/core/anonymization/strategies/date.py +218 -0
  30. confiture/core/anonymization/strategies/differential_privacy.py +398 -0
  31. confiture/core/anonymization/strategies/email.py +141 -0
  32. confiture/core/anonymization/strategies/format_preserving_encryption.py +310 -0
  33. confiture/core/anonymization/strategies/hash.py +150 -0
  34. confiture/core/anonymization/strategies/ip_address.py +235 -0
  35. confiture/core/anonymization/strategies/masking_retention.py +252 -0
  36. confiture/core/anonymization/strategies/name.py +298 -0
  37. confiture/core/anonymization/strategies/phone.py +119 -0
  38. confiture/core/anonymization/strategies/preserve.py +85 -0
  39. confiture/core/anonymization/strategies/redact.py +101 -0
  40. confiture/core/anonymization/strategies/salted_hashing.py +322 -0
  41. confiture/core/anonymization/strategies/text_redaction.py +183 -0
  42. confiture/core/anonymization/strategies/tokenization.py +334 -0
  43. confiture/core/anonymization/strategy.py +241 -0
  44. confiture/core/anonymization/syncer_audit.py +357 -0
  45. confiture/core/blue_green.py +683 -0
  46. confiture/core/builder.py +500 -0
  47. confiture/core/checksum.py +358 -0
  48. confiture/core/connection.py +132 -0
  49. confiture/core/differ.py +522 -0
  50. confiture/core/drift.py +564 -0
  51. confiture/core/dry_run.py +182 -0
  52. confiture/core/health.py +313 -0
  53. confiture/core/hooks/__init__.py +87 -0
  54. confiture/core/hooks/base.py +232 -0
  55. confiture/core/hooks/context.py +146 -0
  56. confiture/core/hooks/execution_strategies.py +57 -0
  57. confiture/core/hooks/observability.py +220 -0
  58. confiture/core/hooks/phases.py +53 -0
  59. confiture/core/hooks/registry.py +295 -0
  60. confiture/core/large_tables.py +775 -0
  61. confiture/core/linting/__init__.py +70 -0
  62. confiture/core/linting/composer.py +192 -0
  63. confiture/core/linting/libraries/__init__.py +17 -0
  64. confiture/core/linting/libraries/gdpr.py +168 -0
  65. confiture/core/linting/libraries/general.py +184 -0
  66. confiture/core/linting/libraries/hipaa.py +144 -0
  67. confiture/core/linting/libraries/pci_dss.py +104 -0
  68. confiture/core/linting/libraries/sox.py +120 -0
  69. confiture/core/linting/schema_linter.py +491 -0
  70. confiture/core/linting/versioning.py +151 -0
  71. confiture/core/locking.py +389 -0
  72. confiture/core/migration_generator.py +298 -0
  73. confiture/core/migrator.py +793 -0
  74. confiture/core/observability/__init__.py +44 -0
  75. confiture/core/observability/audit.py +323 -0
  76. confiture/core/observability/logging.py +187 -0
  77. confiture/core/observability/metrics.py +174 -0
  78. confiture/core/observability/tracing.py +192 -0
  79. confiture/core/pg_version.py +418 -0
  80. confiture/core/pool.py +406 -0
  81. confiture/core/risk/__init__.py +39 -0
  82. confiture/core/risk/predictor.py +188 -0
  83. confiture/core/risk/scoring.py +248 -0
  84. confiture/core/rollback_generator.py +388 -0
  85. confiture/core/schema_analyzer.py +769 -0
  86. confiture/core/schema_to_schema.py +590 -0
  87. confiture/core/security/__init__.py +32 -0
  88. confiture/core/security/logging.py +201 -0
  89. confiture/core/security/validation.py +416 -0
  90. confiture/core/signals.py +371 -0
  91. confiture/core/syncer.py +540 -0
  92. confiture/exceptions.py +192 -0
  93. confiture/integrations/__init__.py +0 -0
  94. confiture/models/__init__.py +0 -0
  95. confiture/models/lint.py +193 -0
  96. confiture/models/migration.py +180 -0
  97. confiture/models/schema.py +203 -0
  98. confiture/scenarios/__init__.py +36 -0
  99. confiture/scenarios/compliance.py +586 -0
  100. confiture/scenarios/ecommerce.py +199 -0
  101. confiture/scenarios/financial.py +253 -0
  102. confiture/scenarios/healthcare.py +315 -0
  103. confiture/scenarios/multi_tenant.py +340 -0
  104. confiture/scenarios/saas.py +295 -0
  105. confiture/testing/FRAMEWORK_API.md +722 -0
  106. confiture/testing/__init__.py +38 -0
  107. confiture/testing/fixtures/__init__.py +11 -0
  108. confiture/testing/fixtures/data_validator.py +229 -0
  109. confiture/testing/fixtures/migration_runner.py +167 -0
  110. confiture/testing/fixtures/schema_snapshotter.py +352 -0
  111. confiture/testing/frameworks/__init__.py +10 -0
  112. confiture/testing/frameworks/mutation.py +587 -0
  113. confiture/testing/frameworks/performance.py +479 -0
  114. confiture/testing/utils/__init__.py +0 -0
  115. fraiseql_confiture-0.3.4.dist-info/METADATA +438 -0
  116. fraiseql_confiture-0.3.4.dist-info/RECORD +119 -0
  117. fraiseql_confiture-0.3.4.dist-info/WHEEL +4 -0
  118. fraiseql_confiture-0.3.4.dist-info/entry_points.txt +2 -0
  119. fraiseql_confiture-0.3.4.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,722 @@
1
+ # Confiture Testing Framework - API Reference
2
+
3
+ Complete API documentation for the Confiture migration testing framework.
4
+
5
+ ## Package Structure
6
+
7
+ ```
8
+ confiture.testing/
9
+ ├── __init__.py
10
+ ├── FRAMEWORK_API.md (This file)
11
+ ├── frameworks/
12
+ │ ├── __init__.py
13
+ │ ├── mutation.py (Mutation testing framework)
14
+ │ └── performance.py (Performance profiling framework)
15
+ └── fixtures/
16
+ ├── __init__.py
17
+ ├── migration_runner.py (Migration execution)
18
+ ├── schema_snapshotter.py (Schema capture/comparison)
19
+ └── data_validator.py (Data integrity validation)
20
+ ```
21
+
22
+ ## Quick Reference
23
+
24
+ ### Main Classes
25
+
26
+ | Class | Module | Purpose |
27
+ |-------|--------|---------|
28
+ | `MutationRegistry` | `frameworks.mutation` | Catalog of test-killing mutations |
29
+ | `MutationRunner` | `frameworks.mutation` | Execute mutations and track results |
30
+ | `MutationReport` | `frameworks.mutation` | Analyze mutation testing results |
31
+ | `MigrationPerformanceProfiler` | `frameworks.performance` | Profile operation timing |
32
+ | `PerformanceProfile` | `frameworks.performance` | Single operation metrics |
33
+ | `PerformanceBaseline` | `frameworks.performance` | Track performance over time |
34
+ | `MigrationRunner` | `fixtures.migration_runner` | Execute migrations |
35
+ | `SchemaSnapshotter` | `fixtures.schema_snapshotter` | Capture schema state |
36
+ | `DataValidator` | `fixtures.data_validator` | Validate data integrity |
37
+
38
+ ## Mutation Testing Framework
39
+
40
+ ### MutationRegistry
41
+
42
+ Provides catalog of mutations for test quality validation.
43
+
44
+ **Import:**
45
+ ```python
46
+ from confiture.testing.frameworks.mutation import MutationRegistry
47
+ ```
48
+
49
+ **Constructor:**
50
+ ```python
51
+ registry = MutationRegistry()
52
+ ```
53
+
54
+ **Properties:**
55
+
56
+ | Property | Type | Description |
57
+ |----------|------|-------------|
58
+ | `mutations` | `dict[str, list[Mutation]]` | All mutations organized by category |
59
+ | `schema_mutations` | `list[Mutation]` | SCHEMA category mutations |
60
+ | `data_mutations` | `list[Mutation]` | DATA category mutations |
61
+ | `rollback_mutations` | `list[Mutation]` | ROLLBACK category mutations |
62
+ | `performance_mutations` | `list[Mutation]` | PERFORMANCE category mutations |
63
+
64
+ **Methods:**
65
+
66
+ ```python
67
+ # Get all mutations for a category
68
+ schema_mutations = registry.get_category_mutations("SCHEMA")
69
+ # Returns: list[Mutation]
70
+
71
+ # Get a specific mutation by ID
72
+ mutation = registry.get_mutation_by_id("SCH_001")
73
+ # Returns: Mutation or None
74
+
75
+ # Get all mutations
76
+ all_mutations = registry.get_all_mutations()
77
+ # Returns: list[Mutation]
78
+
79
+ # Check mutation availability
80
+ has_mutation = registry.has_mutation("SCH_001")
81
+ # Returns: bool
82
+
83
+ # Get mutations by severity
84
+ critical = registry.get_mutations_by_severity("CRITICAL")
85
+ # Returns: list[Mutation]
86
+ ```
87
+
88
+ **Mutation Categories:**
89
+
90
+ | Category | Count | Purpose |
91
+ |----------|-------|---------|
92
+ | SCHEMA | 6 | DDL operation changes |
93
+ | DATA | 7 | Data manipulation changes |
94
+ | ROLLBACK | 5 | Rollback operation changes |
95
+ | PERFORMANCE | 6 | Performance threshold changes |
96
+
97
+ **Example Usage:**
98
+
99
+ ```python
100
+ from confiture.testing.frameworks.mutation import MutationRegistry
101
+
102
+ registry = MutationRegistry()
103
+
104
+ # Get schema mutations
105
+ schema_mutations = registry.schema_mutations
106
+ for mutation in schema_mutations:
107
+ print(f"{mutation.id}: {mutation.description}")
108
+
109
+ # Check specific mutation
110
+ if registry.has_mutation("SCH_002"):
111
+ mutation = registry.get_mutation_by_id("SCH_002")
112
+ print(f"Severity: {mutation.severity}")
113
+ print(f"Category: {mutation.category}")
114
+ print(f"Apply function: {mutation.apply_function}")
115
+ ```
116
+
117
+ ### Mutation
118
+
119
+ Represents a single mutation for test validation.
120
+
121
+ **Properties:**
122
+
123
+ ```python
124
+ mutation.id # str: Mutation identifier (e.g., "SCH_001")
125
+ mutation.description # str: Human-readable description
126
+ mutation.category # str: Category (SCHEMA, DATA, ROLLBACK, PERFORMANCE)
127
+ mutation.severity # str: CRITICAL, HIGH, MEDIUM, LOW
128
+ mutation.apply_function # callable: Function to apply mutation
129
+ mutation.keywords # list[str]: Keywords for filtering
130
+ ```
131
+
132
+ **Example:**
133
+
134
+ ```python
135
+ mutation = registry.get_mutation_by_id("SCH_001")
136
+
137
+ print(f"ID: {mutation.id}")
138
+ print(f"Description: {mutation.description}")
139
+ print(f"Category: {mutation.category}")
140
+ print(f"Severity: {mutation.severity}")
141
+
142
+ # Apply mutation
143
+ modified_sql = mutation.apply_function(original_sql)
144
+ ```
145
+
146
+ ### MutationRunner
147
+
148
+ Executes mutations and tracks test results.
149
+
150
+ **Import:**
151
+ ```python
152
+ from confiture.testing.frameworks.mutation import MutationRunner
153
+ ```
154
+
155
+ **Constructor:**
156
+ ```python
157
+ runner = MutationRunner(registry=None, verbose=True)
158
+ # registry: Optional MutationRegistry (creates new if None)
159
+ # verbose: bool - Enable detailed output
160
+ ```
161
+
162
+ **Methods:**
163
+
164
+ ```python
165
+ # Run mutation suite
166
+ report = runner.run_mutation_suite(registry)
167
+ # Returns: MutationReport
168
+
169
+ # Run single mutation
170
+ result = runner.run_mutation(mutation, test_function)
171
+ # mutation: Mutation
172
+ # test_function: callable(mutation) -> bool
173
+ # Returns: MutationTestResult
174
+
175
+ # Run with custom settings
176
+ report = runner.run_mutation_suite(
177
+ registry,
178
+ timeout_seconds=300,
179
+ max_mutations=None # None = all mutations
180
+ )
181
+ # Returns: MutationReport
182
+ ```
183
+
184
+ **Example:**
185
+
186
+ ```python
187
+ from confiture.testing.frameworks.mutation import MutationRunner
188
+
189
+ runner = MutationRunner()
190
+
191
+ # Define test function
192
+ def test_with_mutation(mutation):
193
+ """Test that should be killed by mutation."""
194
+ try:
195
+ # Run migration with mutation applied
196
+ result = execute_migration_with_mutation(mutation)
197
+
198
+ # Test should detect the mutation
199
+ assert result.schema_valid, "Mutation not detected!"
200
+ return True # Mutation killed
201
+ except AssertionError:
202
+ return False # Mutation survived
203
+
204
+ # Run test suite
205
+ report = runner.run_mutation_suite(registry)
206
+ print(f"Kill rate: {report.kill_rate}%")
207
+ ```
208
+
209
+ ### MutationReport
210
+
211
+ Analysis of mutation testing results.
212
+
213
+ **Properties:**
214
+
215
+ ```python
216
+ report.total_mutations # int: Total mutations in suite
217
+ report.killed_mutations # int: Mutations that failed tests
218
+ report.survived_mutations # int: Mutations that passed tests
219
+ report.error_mutations # int: Mutations with errors
220
+ report.results # list[MutationResult]: Individual results
221
+ report.timestamp # datetime: Report generation time
222
+ report.duration_seconds # float: Total execution time
223
+ ```
224
+
225
+ **Methods:**
226
+
227
+ ```python
228
+ # Calculate kill rate (test quality metric)
229
+ kill_rate = report.calculate_kill_rate()
230
+ # Returns: float (0-100)
231
+
232
+ # Get statistics
233
+ stats = report.get_statistics()
234
+ # Returns: dict with metrics
235
+
236
+ # Find weak areas (survived mutations)
237
+ weak = report.get_survived_mutations()
238
+ # Returns: list[Mutation]
239
+
240
+ # Get summary
241
+ summary = report.get_summary()
242
+ # Returns: str - Human-readable summary
243
+
244
+ # Export results
245
+ json_data = report.to_json()
246
+ # Returns: str - JSON representation
247
+ ```
248
+
249
+ **Example:**
250
+
251
+ ```python
252
+ report = runner.run_mutation_suite(registry)
253
+
254
+ # Check kill rate
255
+ kill_rate = report.calculate_kill_rate()
256
+ print(f"Test quality: {kill_rate}%")
257
+
258
+ if kill_rate < 80:
259
+ print("Tests need improvement - low mutation kill rate")
260
+
261
+ # Find weak areas
262
+ survived = report.get_survived_mutations()
263
+ for mutation in survived:
264
+ print(f"Weak test coverage: {mutation.description}")
265
+ ```
266
+
267
+ ## Performance Framework
268
+
269
+ ### MigrationPerformanceProfiler
270
+
271
+ Profiles migration operation execution times.
272
+
273
+ **Import:**
274
+ ```python
275
+ from confiture.testing.frameworks.performance import MigrationPerformanceProfiler
276
+ ```
277
+
278
+ **Constructor:**
279
+ ```python
280
+ profiler = MigrationPerformanceProfiler()
281
+ ```
282
+
283
+ **Methods:**
284
+
285
+ ```python
286
+ # Profile a migration operation
287
+ profile = profiler.profile_operation(
288
+ operation="CREATE TABLE",
289
+ sql="CREATE TABLE users (id UUID PRIMARY KEY)",
290
+ db_connection=conn # Optional
291
+ )
292
+ # Returns: PerformanceProfile
293
+
294
+ # Profile with custom timeout
295
+ profile = profiler.profile_operation(
296
+ operation="Complex Migration",
297
+ sql=complex_sql,
298
+ timeout_seconds=60
299
+ )
300
+
301
+ # Get baseline
302
+ baseline = profiler.get_baseline()
303
+ # Returns: PerformanceBaseline or None
304
+ ```
305
+
306
+ **Example:**
307
+
308
+ ```python
309
+ from confiture.testing.frameworks.performance import MigrationPerformanceProfiler
310
+ import psycopg
311
+
312
+ profiler = MigrationPerformanceProfiler()
313
+
314
+ # Connect to database
315
+ conn = psycopg.connect("postgresql://localhost/confiture_test")
316
+
317
+ # Profile CREATE TABLE operation
318
+ profile = profiler.profile_operation(
319
+ operation="CREATE TABLE users",
320
+ sql="CREATE TABLE users (id UUID PRIMARY KEY, name VARCHAR(255))",
321
+ db_connection=conn
322
+ )
323
+
324
+ print(f"Duration: {profile.duration_seconds}s")
325
+ print(f"Success: {profile.success}")
326
+
327
+ conn.close()
328
+ ```
329
+
330
+ ### PerformanceProfile
331
+
332
+ Single operation performance metrics.
333
+
334
+ **Properties:**
335
+
336
+ ```python
337
+ profile.operation # str: Operation name
338
+ profile.duration_seconds # float: Execution duration
339
+ profile.timestamp # str: ISO timestamp
340
+ profile.success # bool: Operation succeeded
341
+ profile.memory_mb # Optional[float]: Memory used
342
+ profile.query_plan # Optional[str]: EXPLAIN output
343
+ ```
344
+
345
+ **Methods:**
346
+
347
+ ```python
348
+ # Check against threshold
349
+ is_slow = profile.is_regression(baseline_seconds=1.0, threshold_pct=20)
350
+ # Returns: bool
351
+
352
+ # Calculate regression percentage
353
+ regression = profile.calculate_regression(baseline_seconds=1.0)
354
+ # Returns: float (-50 to 100+)
355
+
356
+ # Get summary
357
+ summary = profile.get_summary()
358
+ # Returns: str - Human-readable summary
359
+ ```
360
+
361
+ **Example:**
362
+
363
+ ```python
364
+ # Check if operation is slow
365
+ if profile.duration_seconds > 5.0:
366
+ print(f"⚠️ Slow operation: {profile.duration_seconds}s")
367
+
368
+ # Check regression against baseline
369
+ if profile.is_regression(baseline_seconds=1.0, threshold_pct=20):
370
+ print("Performance regression detected!")
371
+ regression_pct = profile.calculate_regression(1.0)
372
+ print(f" Increase: {regression_pct}%")
373
+ ```
374
+
375
+ ### PerformanceBaseline
376
+
377
+ Tracks performance metrics over time for regression detection.
378
+
379
+ **Import:**
380
+ ```python
381
+ from confiture.testing.frameworks.performance import PerformanceBaseline
382
+ ```
383
+
384
+ **Constructor:**
385
+ ```python
386
+ baseline = PerformanceBaseline()
387
+ ```
388
+
389
+ **Methods:**
390
+
391
+ ```python
392
+ # Add a performance profile
393
+ baseline.add_profile(
394
+ operation_name="CREATE TABLE",
395
+ duration_seconds=0.5
396
+ )
397
+ # Returns: None
398
+
399
+ # Get baseline for operation
400
+ operation_baseline = baseline.get_baseline("CREATE TABLE")
401
+ # Returns: PerformanceProfile or None
402
+
403
+ # Check for regression
404
+ is_regression = baseline.detect_regression(
405
+ operation="CREATE TABLE",
406
+ current_seconds=0.6,
407
+ threshold_pct=20 # 20% increase
408
+ )
409
+ # Returns: bool
410
+
411
+ # Get all baselines
412
+ baselines = baseline.get_all_baselines()
413
+ # Returns: dict[str, PerformanceProfile]
414
+
415
+ # Statistics
416
+ stats = baseline.get_statistics()
417
+ # Returns: dict with min, max, average times
418
+ ```
419
+
420
+ **Example:**
421
+
422
+ ```python
423
+ from confiture.testing.frameworks.performance import PerformanceBaseline
424
+
425
+ baseline = PerformanceBaseline()
426
+
427
+ # Load historical baselines
428
+ baseline.add_profile("CREATE TABLE", 0.5)
429
+ baseline.add_profile("CREATE INDEX", 1.2)
430
+ baseline.add_profile("Bulk Insert 10k", 8.5)
431
+
432
+ # Check if new operation is regression
433
+ if baseline.detect_regression("CREATE TABLE", 0.65, threshold_pct=20):
434
+ print("Performance regression: CREATE TABLE now takes 30% longer")
435
+
436
+ # Get statistics
437
+ stats = baseline.get_statistics()
438
+ print(f"Average CREATE TABLE time: {stats['average']}s")
439
+ ```
440
+
441
+ ## Fixtures
442
+
443
+ ### test_db_connection
444
+
445
+ Provides PostgreSQL database connection for tests.
446
+
447
+ **Usage:**
448
+ ```python
449
+ def test_example(test_db_connection):
450
+ """Test using database connection fixture."""
451
+ with test_db_connection.cursor() as cur:
452
+ cur.execute("CREATE TABLE test (id UUID PRIMARY KEY)")
453
+ test_db_connection.commit()
454
+ ```
455
+
456
+ **Database Details:**
457
+ ```python
458
+ # Connection string
459
+ DATABASE_URL: postgresql://confiture:confiture@localhost:5432/confiture_test
460
+
461
+ # Auto-cleanup
462
+ # Connection automatically closes after test
463
+ ```
464
+
465
+ ### temp_project_dir
466
+
467
+ Provides temporary project directory for test files.
468
+
469
+ **Usage:**
470
+ ```python
471
+ def test_with_files(temp_project_dir):
472
+ """Test using temporary directory."""
473
+ migration_file = temp_project_dir / "001_create_table.sql"
474
+ migration_file.write_text("CREATE TABLE test (...)")
475
+
476
+ assert migration_file.exists()
477
+ ```
478
+
479
+ ### sample_confiture_schema
480
+
481
+ Provides sample PostgreSQL schema files.
482
+
483
+ **Usage:**
484
+ ```python
485
+ def test_with_schema(sample_confiture_schema, test_db_connection):
486
+ """Test using sample schema."""
487
+ with test_db_connection.cursor() as cur:
488
+ # sample_confiture_schema is dict[str, Path]
489
+ users_sql = sample_confiture_schema["users"].read_text()
490
+ cur.execute(users_sql)
491
+ test_db_connection.commit()
492
+ ```
493
+
494
+ **Available Schemas:**
495
+ ```python
496
+ sample_confiture_schema = {
497
+ "extensions.sql": Path(...), # PostgreSQL extensions
498
+ "users.sql": Path(...), # Users table
499
+ "posts.sql": Path(...), # Posts table
500
+ "comments.sql": Path(...), # Comments table
501
+ "user_stats.sql": Path(...), # User aggregates
502
+ }
503
+ ```
504
+
505
+ ### mutation_registry
506
+
507
+ Provides configured MutationRegistry for tests.
508
+
509
+ **Usage:**
510
+ ```python
511
+ def test_with_mutations(mutation_registry):
512
+ """Test using mutation framework."""
513
+ # mutation_registry is pre-configured MutationRegistry
514
+
515
+ schema_mutations = mutation_registry.schema_mutations
516
+ for mutation in schema_mutations:
517
+ # Test mutation killing
518
+ pass
519
+ ```
520
+
521
+ ### performance_profiler
522
+
523
+ Provides configured PerformanceProfiler for tests.
524
+
525
+ **Usage:**
526
+ ```python
527
+ def test_with_performance(performance_profiler, test_db_connection):
528
+ """Test using performance profiling."""
529
+ profile = performance_profiler.profile_operation(
530
+ operation="CREATE TABLE",
531
+ sql="CREATE TABLE test (...)",
532
+ db_connection=test_db_connection
533
+ )
534
+
535
+ assert profile.duration_seconds < 5.0
536
+ ```
537
+
538
+ ## Common Patterns
539
+
540
+ ### Testing Forward Migration
541
+
542
+ ```python
543
+ def test_forward_migration(test_db_connection):
544
+ """Test forward migration succeeds and validates schema."""
545
+ with test_db_connection.cursor() as cur:
546
+ # Create table
547
+ cur.execute("""
548
+ CREATE TABLE users (
549
+ id UUID PRIMARY KEY,
550
+ name VARCHAR(255) NOT NULL
551
+ )
552
+ """)
553
+ test_db_connection.commit()
554
+
555
+ # Validate schema
556
+ cur.execute("""
557
+ SELECT column_name, data_type
558
+ FROM information_schema.columns
559
+ WHERE table_name = 'users'
560
+ """)
561
+
562
+ columns = {row[0]: row[1] for row in cur.fetchall()}
563
+ assert 'id' in columns
564
+ assert 'name' in columns
565
+ ```
566
+
567
+ ### Testing Rollback Safety
568
+
569
+ ```python
570
+ def test_rollback_safe(test_db_connection):
571
+ """Test rollback preserves data integrity."""
572
+ with test_db_connection.cursor() as cur:
573
+ # Create and populate table
574
+ cur.execute("CREATE TABLE data (id UUID PRIMARY KEY, value INT)")
575
+ cur.execute("INSERT INTO data VALUES (gen_random_uuid(), 42)")
576
+ test_db_connection.commit()
577
+
578
+ # Simulate migration
579
+ cur.execute("ALTER TABLE data ADD COLUMN new_col VARCHAR(255)")
580
+ test_db_connection.commit()
581
+
582
+ # Simulate rollback
583
+ cur.execute("ALTER TABLE data DROP COLUMN new_col")
584
+ test_db_connection.commit()
585
+
586
+ # Verify original data intact
587
+ cur.execute("SELECT COUNT(*) FROM data WHERE value = 42")
588
+ assert cur.fetchone()[0] == 1
589
+ ```
590
+
591
+ ### Testing Performance
592
+
593
+ ```python
594
+ def test_performance(test_db_connection, performance_profiler):
595
+ """Test operation performance against threshold."""
596
+ import time
597
+
598
+ with test_db_connection.cursor() as cur:
599
+ # Setup
600
+ cur.execute("""
601
+ CREATE TABLE perf_test (
602
+ id UUID PRIMARY KEY,
603
+ data BIGINT
604
+ )
605
+ """)
606
+ test_db_connection.commit()
607
+
608
+ # Measure bulk insert
609
+ start = time.time()
610
+ cur.execute("""
611
+ INSERT INTO perf_test (id, data)
612
+ SELECT gen_random_uuid(), i FROM generate_series(1, 10000) i
613
+ """)
614
+ test_db_connection.commit()
615
+ duration = time.time() - start
616
+
617
+ # Assert within threshold
618
+ assert duration < 30.0, f"Bulk insert took {duration}s (> 30s)"
619
+ ```
620
+
621
+ ## Error Handling
622
+
623
+ ### Database Errors
624
+
625
+ ```python
626
+ def test_with_error_handling(test_db_connection):
627
+ """Handle database errors gracefully."""
628
+ try:
629
+ with test_db_connection.cursor() as cur:
630
+ # This will fail - table doesn't exist
631
+ cur.execute("INSERT INTO nonexistent VALUES (1)")
632
+ test_db_connection.commit()
633
+ except Exception as e:
634
+ test_db_connection.rollback()
635
+ print(f"Expected error: {e}")
636
+ ```
637
+
638
+ ### Timeout Handling
639
+
640
+ ```python
641
+ def test_with_timeout(test_db_connection):
642
+ """Handle operation timeouts."""
643
+ try:
644
+ with test_db_connection.cursor() as cur:
645
+ # Set timeout for long operation
646
+ cur.execute("SET statement_timeout TO '5s'")
647
+
648
+ # This might timeout
649
+ cur.execute("SELECT * FROM generate_series(1, 1000000)")
650
+ except TimeoutError:
651
+ print("Operation timed out")
652
+ ```
653
+
654
+ ## Environment Variables
655
+
656
+ ```bash
657
+ # PostgreSQL Connection
658
+ DATABASE_URL=postgresql://confiture:confiture@localhost:5432/confiture_test
659
+ POSTGRES_HOST=localhost
660
+ POSTGRES_PORT=5432
661
+ POSTGRES_USER=confiture
662
+ POSTGRES_PASSWORD=confiture
663
+ POSTGRES_DB=confiture_test
664
+
665
+ # Performance Thresholds
666
+ PERF_CREATE_TABLE_THRESHOLD=5.0 # seconds
667
+ PERF_CREATE_INDEX_THRESHOLD=10.0 # seconds
668
+ PERF_BULK_INSERT_10K_THRESHOLD=30.0 # seconds
669
+
670
+ # Mutation Testing
671
+ MUTATION_TIMEOUT=300 # seconds
672
+ MUTATION_VERBOSE=true # Enable detailed output
673
+ ```
674
+
675
+ ## Best Practices
676
+
677
+ 1. **Use Fixtures**: Always use provided fixtures for database access
678
+ 2. **Clean Up**: Always drop tables created with `DROP TABLE IF EXISTS`
679
+ 3. **Isolate Tests**: Each test should be independent
680
+ 4. **Use Assertions**: Clear assertion messages for failures
681
+ 5. **Document Tests**: Include docstrings explaining test purpose
682
+ 6. **Handle Transactions**: Explicitly commit/rollback
683
+ 7. **Check Performance**: Always assert performance thresholds
684
+ 8. **Verify Data**: Validate data integrity after operations
685
+
686
+ ## Troubleshooting
687
+
688
+ ### "Database connection failed"
689
+
690
+ ```bash
691
+ # Check PostgreSQL is running
692
+ pg_isready -h localhost -p 5432
693
+
694
+ # Verify credentials
695
+ psql -h localhost -U confiture -d confiture_test
696
+ ```
697
+
698
+ ### "Mutation not detected"
699
+
700
+ ```python
701
+ # Make sure test actually validates the mutation
702
+ # Good:
703
+ assert migrated_schema.columns['id'].type == 'UUID'
704
+
705
+ # Bad:
706
+ assert True # Always passes, mutation not detected
707
+ ```
708
+
709
+ ### "Performance regression detected"
710
+
711
+ ```python
712
+ # Review recent commits for performance impacts
713
+ # Run test in isolation
714
+ uv run pytest tests/migration_testing/test_performance.py -v --durations=10
715
+ ```
716
+
717
+ ## Additional Resources
718
+
719
+ - [Confiture Documentation](https://github.com/your-org/confiture)
720
+ - [PostgreSQL Documentation](https://www.postgresql.org/docs/)
721
+ - [psycopg3 Documentation](https://www.psycopg.org/)
722
+ - [pytest Documentation](https://docs.pytest.org/)