Aufgaben-Python/courses/go/11_select_und_timeouts/test_aufgabe.go

117 lines
3.7 KiB
Go

package main
import (
"context"
"errors"
"fmt"
"time"
)
// 🧪 GO 11 TESTSUITE: select, Timeouts & Context
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: TestFastestResponse - Prüft select über zwei Kanäle
func TestFastestResponse() {
fmt.Println("=== RUN TestFastestResponse")
ch1 := make(chan string, 1)
ch2 := make(chan string, 1)
ch1 <- "Fast-1"
res := FastestResponse(ch1, ch2)
assertEquals(res, "Fast-1", "Sollte den bereiten Kanal ch1 wählen")
ch2 <- "Fast-2"
res2 := FastestResponse(ch1, ch2)
assertEquals(res2, "Fast-2", "Sollte den bereiten Kanal ch2 wählen")
fmt.Println("--- PASS: TestFastestResponse")
}
// TEST: TestFetchWithTimeout - Prüft Datenempfang vs. Timeout
func TestFetchWithTimeout() {
fmt.Println("=== RUN TestFetchWithTimeout")
// 1. Erfolgreicher Empfang
readyCh := make(chan string, 1)
readyCh <- "Data-OK"
res, err := FetchWithTimeout(readyCh, 100*time.Millisecond)
assertEquals(err, nil, "Sollte keinen Fehler werfen bei bereiten Daten")
assertEquals(res, "Data-OK", "Daten müssen übereinstimmen")
// 2. Timeout-Fall
slowCh := make(chan string) // Nie befüllt
start := time.Now()
_, errTimeout := FetchWithTimeout(slowCh, 30*time.Millisecond)
duration := time.Since(start)
assert(errTimeout != nil, "Sollte bei blockiertem Kanal einen Timeout-Fehler liefern")
assert(duration >= 25*time.Millisecond, "Sollte mindestens die angegebene Timeout-Dauer warten")
fmt.Println("--- PASS: TestFetchWithTimeout")
}
// TEST: TestNonBlockingOperations - Prüft TrySend und TryReceive
func TestNonBlockingOperations() {
fmt.Println("=== RUN TestNonBlockingOperations")
ch := make(chan int, 1)
// 1. TrySend auf leeren Puffer
okSend1 := TrySend(ch, 42)
assertEquals(okSend1, true, "Erstes TrySend in Puffer (Größe 1) muss erfolgreich sein")
// 2. TrySend auf vollen Puffer
okSend2 := TrySend(ch, 99)
assertEquals(okSend2, false, "Zweites TrySend in vollen Puffer muss false liefern")
// 3. TryReceive mit Daten
val, okRecv1 := TryReceive(ch)
assertEquals(okRecv1, true, "TryReceive muss true liefern bei vorhandenen Daten")
assertEquals(val, 42, "Gelesener Wert muss 42 sein")
// 4. TryReceive auf leerem Channel
_, okRecv2 := TryReceive(ch)
assertEquals(okRecv2, false, "TryReceive auf leerem Channel muss false liefern")
fmt.Println("--- PASS: TestNonBlockingOperations")
}
// TEST: TestQueryWithContext - Prüft Context Cancellation und Deadlines
func TestQueryWithContext() {
fmt.Println("=== RUN TestQueryWithContext")
// 1. Erfolgreicher Context
ctxSuccess, cancel1 := context.WithTimeout(context.Background(), 200*time.Millisecond)
defer cancel1()
res, err := QueryWithContext(ctxSuccess, func() string {
return "DB-Data"
})
assertEquals(err, nil, "Sollte erfolgreich sein")
assertEquals(res, "DB-Data", "Ergebnis muss DB-Data sein")
// 2. Timeout Context
ctxTimeout, cancel2 := context.WithTimeout(context.Background(), 20*time.Millisecond)
defer cancel2()
_, errTimeout := QueryWithContext(ctxTimeout, func() string {
time.Sleep(100 * time.Millisecond)
return "Too-Late"
})
assert(errors.Is(errTimeout, context.DeadlineExceeded), "Fehler muss context.DeadlineExceeded sein")
fmt.Println("--- PASS: TestQueryWithContext")
}
func main() {
fmt.Println("🧪 Starte Go 11 Testsuite...")
TestFastestResponse()
TestFetchWithTimeout()
TestNonBlockingOperations()
TestQueryWithContext()
fmt.Println("\n✅ Alle Tests in Go 11 erfolgreich bestanden!")
}