119 lines
3.2 KiB
Go
119 lines
3.2 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
)
|
|
|
|
// 🧪 GO 12 TESTSUITE: Mutex, RWMutex & Atomics
|
|
|
|
func assert(condition bool, msg string) {
|
|
if !condition {
|
|
panic("❌ Test fehlgeschlagen: " + msg)
|
|
}
|
|
}
|
|
|
|
func assertEquals[T comparable](actual, expected T, msg string) {
|
|
if actual != expected {
|
|
panic(fmt.Sprintf("❌ Test fehlgeschlagen: %s (Erwartet: '%v', Erhalten: '%v')", msg, expected, actual))
|
|
}
|
|
}
|
|
|
|
// TEST: TestSafeCacheConcurrency - Stresstest mit parallelen Schreibern und Lesern
|
|
func TestSafeCacheConcurrency() {
|
|
fmt.Println("=== RUN TestSafeCacheConcurrency")
|
|
cache := NewSafeCache()
|
|
var wg sync.WaitGroup
|
|
numOps := 100
|
|
|
|
// 100 parallele Schreiber
|
|
for i := 0; i < numOps; i++ {
|
|
wg.Add(1)
|
|
go func(id int) {
|
|
defer wg.Done()
|
|
cache.Set(fmt.Sprintf("k-%d", id), fmt.Sprintf("v-%d", id))
|
|
}(i)
|
|
}
|
|
|
|
// 100 parallele Leser
|
|
for i := 0; i < numOps; i++ {
|
|
wg.Add(1)
|
|
go func(id int) {
|
|
defer wg.Done()
|
|
cache.Get(fmt.Sprintf("k-%d", id))
|
|
}(i)
|
|
}
|
|
|
|
wg.Wait()
|
|
assertEquals(cache.Len(), numOps, "Alle 100 Elemente müssen im Cache vorhanden sein")
|
|
|
|
// Löschen testen
|
|
cache.Delete("k-0")
|
|
assertEquals(cache.Len(), numOps-1, "Cache-Größe muss nach Delete 99 sein")
|
|
_, exists := cache.Get("k-0")
|
|
assertEquals(exists, false, "Gelöschter Key darf nicht mehr existieren")
|
|
fmt.Println("--- PASS: TestSafeCacheConcurrency")
|
|
}
|
|
|
|
// TEST: TestAtomicCounterConcurrency - Stresstest für lock-freie Atomics
|
|
func TestAtomicCounterConcurrency() {
|
|
fmt.Println("=== RUN TestAtomicCounterConcurrency")
|
|
var counter AtomicCounter
|
|
var wg sync.WaitGroup
|
|
numGoroutines := 1000
|
|
|
|
for i := 0; i < numGoroutines; i++ {
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
counter.Inc()
|
|
}()
|
|
}
|
|
|
|
wg.Wait()
|
|
assertEquals(counter.Value(), int64(1000), "Zähler muss nach 1000 atomaren Incs exakt 1000 sein")
|
|
|
|
counter.Add(500)
|
|
assertEquals(counter.Value(), int64(1500), "Add(500) muss Zähler auf 1500 setzen")
|
|
|
|
counter.Reset()
|
|
assertEquals(counter.Value(), int64(0), "Reset() muss Zähler auf 0 zurücksetzen")
|
|
fmt.Println("--- PASS: TestAtomicCounterConcurrency")
|
|
}
|
|
|
|
// TEST: TestSafeBankAccountConcurrency - Prüft Kontoüberweisungen und Schutz vor Überziehung
|
|
func TestSafeBankAccountConcurrency() {
|
|
fmt.Println("=== RUN TestSafeBankAccountConcurrency")
|
|
account := &SafeBankAccount{}
|
|
account.Deposit(1000.0)
|
|
|
|
var wg sync.WaitGroup
|
|
numWithdraws := 10
|
|
|
|
// 10 Goroutines buchen jeweils 50 Euro ab
|
|
for i := 0; i < numWithdraws; i++ {
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
err := account.Withdraw(50.0)
|
|
assert(err == nil, "Auszahlung muss erfolgreich sein")
|
|
}()
|
|
}
|
|
|
|
wg.Wait()
|
|
assertEquals(account.Balance(), 500.0, "Restguthaben muss exakt 500.0 betragen")
|
|
|
|
// Überziehungstest
|
|
errOverdraft := account.Withdraw(600.0)
|
|
assert(errOverdraft != nil, "Überziehung über 500 Euro muss mit Fehler abbrechen")
|
|
assertEquals(account.Balance(), 500.0, "Guthaben darf sich bei fehlgeschlagener Abbuchung nicht ändern")
|
|
fmt.Println("--- PASS: TestSafeBankAccountConcurrency")
|
|
}
|
|
|
|
func main() {
|
|
fmt.Println("🧪 Starte Go 12 Testsuite...")
|
|
TestSafeCacheConcurrency()
|
|
TestAtomicCounterConcurrency()
|
|
TestSafeBankAccountConcurrency()
|
|
fmt.Println("\n✅ Alle Tests in Go 12 erfolgreich bestanden!")
|
|
}
|