Refactor MQTT course and bound backend message processing
Move lesson source into the teaching structure, align the course path with the learner's Go and DevOps experience, and add the interactive lesson guides. Add advanced DevOps lifecycle study as a separate section. Bound MQTT message work and drain accepted jobs during shutdown; align the backend implementation with the revised course through Section 6.
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
package dispatch
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"example.com/mqtt5-learning/internal/mqtt"
|
||||
)
|
||||
|
||||
func TestPoolReportsFullAndDrainsAcceptedJobs(t *testing.T) {
|
||||
pool := New(context.Background(), 1, 1)
|
||||
started := make(chan struct{})
|
||||
release := make(chan struct{})
|
||||
|
||||
outcome, err := pool.Submit(context.Background(), func(context.Context) error {
|
||||
close(started)
|
||||
<-release
|
||||
return nil
|
||||
})
|
||||
if err != nil || outcome != Accepted {
|
||||
t.Fatalf("first Submit() = (%v, %v), want (Accepted, nil)", outcome, err)
|
||||
}
|
||||
<-started
|
||||
|
||||
outcome, err = pool.Submit(context.Background(), func(context.Context) error { return nil })
|
||||
if err != nil || outcome != Accepted {
|
||||
t.Fatalf("second Submit() = (%v, %v), want (Accepted, nil)", outcome, err)
|
||||
}
|
||||
outcome, err = pool.Submit(context.Background(), func(context.Context) error { return nil })
|
||||
if err != nil || outcome != Full {
|
||||
t.Fatalf("third Submit() = (%v, %v), want (Full, nil)", outcome, err)
|
||||
}
|
||||
|
||||
shutdownCtx, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||
defer cancel()
|
||||
shutdownDone := make(chan error, 1)
|
||||
go func() { shutdownDone <- pool.Shutdown(shutdownCtx) }()
|
||||
|
||||
select {
|
||||
case err := <-shutdownDone:
|
||||
t.Fatalf("Shutdown() returned before accepted work was released: %v", err)
|
||||
case <-time.After(10 * time.Millisecond):
|
||||
}
|
||||
close(release)
|
||||
if err := <-shutdownDone; err != nil {
|
||||
t.Fatalf("Shutdown() error = %v, want nil", err)
|
||||
}
|
||||
|
||||
stats := pool.Stats()
|
||||
if stats.Accepted != 2 || stats.Rejected != 1 || stats.Completed != 2 || stats.Failed != 0 {
|
||||
t.Fatalf("Stats() = %+v, want accepted=2 rejected=1 completed=2 failed=0", stats)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReceiverRoutesResponsesToImportantPool(t *testing.T) {
|
||||
telemetry := New(context.Background(), 1, 1)
|
||||
important := New(context.Background(), 1, 1)
|
||||
receiver := &Receiver{
|
||||
Telemetry: telemetry,
|
||||
Important: important,
|
||||
Process: func(context.Context, mqtt.Message) error { return nil },
|
||||
}
|
||||
|
||||
outcome, err := receiver.Submit(context.Background(), mqtt.Message{
|
||||
Topic: "lab/v1/devices/device-001/responses",
|
||||
})
|
||||
if err != nil || outcome != Accepted {
|
||||
t.Fatalf("Submit(response) = (%v, %v), want (Accepted, nil)", outcome, err)
|
||||
}
|
||||
|
||||
shutdownCtx, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||
defer cancel()
|
||||
if err := Shutdown(shutdownCtx, telemetry, important); err != nil {
|
||||
t.Fatalf("Shutdown() error = %v", err)
|
||||
}
|
||||
if got := important.Stats().Accepted; got != 1 {
|
||||
t.Errorf("important accepted = %d, want 1", got)
|
||||
}
|
||||
if got := telemetry.Stats().Accepted; got != 0 {
|
||||
t.Errorf("telemetry accepted = %d, want 0", got)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user