20-02-2026
This commit is contained in:
parent
a8b395e20d
commit
a00c42e770
252 changed files with 28785 additions and 8907 deletions
178
tests/Feature/Payment/README.md
Normal file
178
tests/Feature/Payment/README.md
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
# Payment Race Condition Tests
|
||||
|
||||
Diese Test-Suite überprüft die Behebung von Race Conditions bei der Zahlungsabwicklung und Rechnungsnummernvergabe.
|
||||
|
||||
## Übersicht
|
||||
|
||||
### Problem
|
||||
Wenn mehrere Zahlungen fast gleichzeitig über die Payone API eingehen, konnte es zu Race Conditions kommen:
|
||||
- Doppelte Rechnungsnummern
|
||||
- Mehrfache Verarbeitung derselben Zahlung
|
||||
- Inkonsistente Datenbank-Zustände
|
||||
|
||||
### Lösung
|
||||
3-Stufen-Absicherung implementiert:
|
||||
1. **Database Locking** im PayoneController mit `lockForUpdate()`
|
||||
2. **Atomic Invoice Number** Vergabe mit Transaction + Lock
|
||||
3. **Double-Check Pattern** zur zusätzlichen Absicherung
|
||||
|
||||
## Test-Dateien
|
||||
|
||||
### 1. ConcurrentPaymentTest.php
|
||||
Tests für gleichzeitige Rechnungsnummernvergabe:
|
||||
|
||||
- ✅ `it_generates_unique_invoice_numbers_under_concurrent_load()` - Eindeutigkeit bei hoher Last
|
||||
- ✅ `it_atomically_increments_invoice_numbers()` - Atomare Inkrementierung
|
||||
- ✅ `it_does_not_skip_invoice_numbers_on_transaction_rollback()` - Keine Lücken
|
||||
- ✅ `it_uses_database_locking_for_invoice_numbers()` - Lock-Mechanismus
|
||||
- ✅ `it_prevents_double_processing_of_same_payment()` - Doppelverarbeitung verhindern
|
||||
- ✅ `it_can_lock_settings_for_update()` - Setting-Lock funktioniert
|
||||
- ✅ `it_creates_invoice_numbers_with_correct_format()` - Korrekte Formatierung
|
||||
- ✅ `it_handles_rapid_sequential_invoice_creation()` - Schnelle Sequenzen
|
||||
- ✅ `it_initializes_invoice_number_if_not_exists()` - Initialisierung
|
||||
- ✅ `it_handles_concurrent_transaction_commits()` - Gleichzeitige Commits
|
||||
|
||||
### 2. PayoneRaceConditionTest.php
|
||||
Tests für Payone-spezifische Race Conditions:
|
||||
|
||||
- ✅ `it_locks_shopping_order_during_payment_processing()` - Order wird gelockt
|
||||
- ✅ `it_prevents_double_payment_processing()` - Doppelte Zahlung verhindern
|
||||
- ✅ `it_serializes_concurrent_payment_requests()` - Serialisierung
|
||||
- ✅ `it_rolls_back_payment_on_error()` - Rollback bei Fehler
|
||||
- ✅ `it_tracks_payment_status_transitions()` - Status-Übergänge
|
||||
- ✅ `it_handles_concurrent_payments_for_different_orders()` - Verschiedene Orders
|
||||
- ✅ `it_isolates_payment_transactions()` - Transaction Isolation
|
||||
- ✅ `it_prevents_concurrent_modifications()` - Gleichzeitige Änderungen verhindern
|
||||
- ✅ `it_enforces_unique_payment_references()` - Eindeutige Referenzen
|
||||
|
||||
### 3. InvoiceServiceTest.php (Unit Tests)
|
||||
Unit-Tests für Invoice Service:
|
||||
|
||||
- ✅ `it_gets_current_invoice_number()` - Nummer abrufen
|
||||
- ✅ `it_increments_invoice_number()` - Inkrementierung
|
||||
- ✅ `it_increments_sequentially()` - Sequenzielle Inkrementierung
|
||||
- ✅ `it_formats_invoice_number_with_year_prefix()` - Formatierung
|
||||
- ✅ `it_generates_correct_storage_paths()` - Storage-Pfade
|
||||
- ✅ `it_generates_correct_filenames()` - Dateinamen
|
||||
- ✅ `it_initializes_invoice_number_when_not_exists()` - Initialisierung
|
||||
- ✅ `it_uses_transaction_for_invoice_number_increment()` - Transaction Usage
|
||||
- ✅ `it_locks_setting_during_increment()` - Lock während Increment
|
||||
- ✅ `it_pads_invoice_numbers_correctly()` - Korrekte Padding
|
||||
- ✅ `it_returns_zero_when_invoice_number_not_set()` - Default-Wert
|
||||
- ✅ `it_handles_rapid_increments_without_gaps()` - Keine Lücken
|
||||
- ✅ `it_returns_integer_invoice_number()` - Typ-Sicherheit
|
||||
|
||||
## Tests ausführen
|
||||
|
||||
### Alle Payment-Tests
|
||||
```bash
|
||||
./vendor/bin/phpunit tests/Feature/Payment/
|
||||
```
|
||||
|
||||
### Einzelne Test-Datei
|
||||
```bash
|
||||
./vendor/bin/phpunit tests/Feature/Payment/ConcurrentPaymentTest.php
|
||||
./vendor/bin/phpunit tests/Feature/Payment/PayoneRaceConditionTest.php
|
||||
./vendor/bin/phpunit tests/Unit/Services/InvoiceServiceTest.php
|
||||
```
|
||||
|
||||
### Einzelner Test
|
||||
```bash
|
||||
./vendor/bin/phpunit --filter it_generates_unique_invoice_numbers_under_concurrent_load
|
||||
```
|
||||
|
||||
### Mit Coverage
|
||||
```bash
|
||||
./vendor/bin/phpunit --coverage-html coverage/ tests/Feature/Payment/
|
||||
```
|
||||
|
||||
### Mit Pest (falls verwendet)
|
||||
```bash
|
||||
./vendor/bin/pest tests/Feature/Payment/
|
||||
```
|
||||
|
||||
## Wichtige Hinweise
|
||||
|
||||
### Database Transactions
|
||||
Alle Tests verwenden `DatabaseTransactions` Trait:
|
||||
- Änderungen werden nach jedem Test automatisch zurückgerollt
|
||||
- Tests sind isoliert und beeinflussen sich nicht gegenseitig
|
||||
- Keine manuelle Datenbank-Bereinigung nötig
|
||||
|
||||
### Test-Daten
|
||||
Tests erstellen eigene Test-Daten:
|
||||
- ShoppingOrder, ShoppingPayment, ShoppingUser
|
||||
- Setting für invoice-number
|
||||
- Alle Daten werden nach Test automatisch entfernt
|
||||
|
||||
### Performance
|
||||
Tests simulieren Concurrent Scenarios:
|
||||
- Verwenden separate DB-Transactions
|
||||
- Testen Lock-Mechanismen
|
||||
- Prüfen auf Race Conditions
|
||||
|
||||
## Continuous Integration
|
||||
|
||||
Diese Tests sollten Teil der CI/CD Pipeline sein:
|
||||
|
||||
```yaml
|
||||
# .github/workflows/tests.yml
|
||||
- name: Run Payment Tests
|
||||
run: ./vendor/bin/phpunit tests/Feature/Payment/
|
||||
```
|
||||
|
||||
## Monitoring in Production
|
||||
|
||||
Nach Deployment überwachen:
|
||||
|
||||
1. **Log-Einträge prüfen:**
|
||||
```bash
|
||||
grep "Error:2008" storage/logs/laravel.log
|
||||
```
|
||||
|
||||
2. **Rechnungsnummern auf Lücken prüfen:**
|
||||
```sql
|
||||
SELECT * FROM user_invoices
|
||||
ORDER BY number
|
||||
-- Prüfe auf Lücken in der Sequenz
|
||||
```
|
||||
|
||||
3. **Doppelte Rechnungsnummern prüfen:**
|
||||
```sql
|
||||
SELECT full_number, COUNT(*)
|
||||
FROM user_invoices
|
||||
GROUP BY full_number
|
||||
HAVING COUNT(*) > 1;
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Test schlägt fehl: "Database not configured"
|
||||
```bash
|
||||
cp .env.example .env.testing
|
||||
php artisan key:generate --env=testing
|
||||
```
|
||||
|
||||
### Test schlägt fehl: "Setting not found"
|
||||
Tests initialisieren automatisch - prüfe Migration:
|
||||
```bash
|
||||
php artisan migrate --env=testing
|
||||
```
|
||||
|
||||
### Test schlägt fehl: "Foreign key constraint"
|
||||
Prüfe, ob alle Referenzen korrekt erstellt werden:
|
||||
```bash
|
||||
php artisan migrate:fresh --env=testing
|
||||
```
|
||||
|
||||
## Weiterführende Informationen
|
||||
|
||||
- **Code-Änderungen:** Siehe Git Commit mit Tag `race-condition-fix`
|
||||
- **Dokumentation:** `/dev/[DATUM]/payment-race-condition-fix.md`
|
||||
- **Issue:** Siehe entsprechendes GitHub Issue
|
||||
|
||||
---
|
||||
|
||||
**Erstellt:** Januar 2026
|
||||
**Autor:** Claude AI Assistant
|
||||
**Status:** ✅ Production Ready
|
||||
Loading…
Add table
Add a link
Reference in a new issue