Aufgaben-Python/courses/go/12_mutex_und_thread_safety/test_aufgabe.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!")
}