Deploy MQTT test backend with private viewer and Gitea CI/CD
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/eclipse/paho.golang/paho"
|
||||
"robot-market/test-mqtt-5/internal/backend"
|
||||
"robot-market/test-mqtt-5/internal/contracts"
|
||||
"robot-market/test-mqtt-5/internal/events"
|
||||
"robot-market/test-mqtt-5/internal/mqtt"
|
||||
)
|
||||
|
||||
func TestRemoteBrokerQueuedMessageExpiry(t *testing.T) {
|
||||
deviceCfg := remoteConfig(t, "sim-001", false)
|
||||
deviceCfg.MQTT.ClientID = "rm5-expiry-" + backend.ID()[:12]
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
device := mqtt.New(deviceCfg, store(deviceCfg))
|
||||
if err := device.Start(ctx, []string{"commands"}, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := device.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
serverCfg := remoteConfig(t, "test-backend", false)
|
||||
server := mqtt.New(serverCfg, store(serverCfg))
|
||||
if err := server.Start(ctx, []string{"acks"}, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer server.Close()
|
||||
// Application deadline remains valid; the broker must expire this queued packet.
|
||||
p := mqtt.Packet(mqtt.Topic(serverCfg, "commands"), 1, false, backend.NewCommand("sim-001", "ping", backend.ID(), 15*time.Second))
|
||||
p.Properties.MessageExpiry = paho.Uint32(1)
|
||||
if err := server.Publish(ctx, p); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
time.Sleep(2 * time.Second)
|
||||
deviceCfg.MQTT.CleanStart = false
|
||||
device = mqtt.New(deviceCfg, store(deviceCfg))
|
||||
if err := device.Start(ctx, []string{"commands"}, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer device.Close()
|
||||
history, _ := device.Events.Snapshot()
|
||||
resumed := false
|
||||
for _, e := range history {
|
||||
if e.Kind == events.ConnectionUp && strings.Contains(e.Outcome, "session_present=true") {
|
||||
resumed = true
|
||||
}
|
||||
}
|
||||
if !resumed {
|
||||
t.Fatal("offline subscriber session was lost; expiry test inconclusive")
|
||||
}
|
||||
select {
|
||||
case <-device.Incoming:
|
||||
t.Fatal("broker delivered expired queued command")
|
||||
case <-time.After(300 * time.Millisecond):
|
||||
}
|
||||
fresh := mqtt.Packet(mqtt.Topic(serverCfg, "commands"), 1, false, backend.NewCommand("sim-001", "ping", backend.ID(), 15*time.Second))
|
||||
if err := server.Publish(ctx, fresh); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
select {
|
||||
case got := <-device.Incoming:
|
||||
if string(got.Payload) != string(fresh.Payload) {
|
||||
t.Fatal("wrong queued packet")
|
||||
}
|
||||
case <-time.After(3 * time.Second):
|
||||
t.Fatal("fresh control command missing")
|
||||
}
|
||||
t.Log("broker expiry distinct from valid application deadline, persistent offline queue, fresh control delivery: PASS")
|
||||
}
|
||||
|
||||
func TestRemoteWillAfterAbruptDisconnect(t *testing.T) {
|
||||
observerCfg := remoteConfig(t, "test-backend", false)
|
||||
observer := mqtt.New(observerCfg, store(observerCfg))
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
if err := observer.Start(ctx, []string{"status"}, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer observer.Close()
|
||||
cfg := remoteConfig(t, "sim-001", false)
|
||||
proxy := newRelay(t, strings.TrimPrefix(cfg.MQTT.URL, "tls://"))
|
||||
defer proxy.close()
|
||||
cfg.MQTT.URL = "tls://" + proxy.listener.Addr().String()
|
||||
cfg.MQTT.ReconnectMin = 100 * time.Millisecond
|
||||
cfg.MQTT.ReconnectMax = 200 * time.Millisecond
|
||||
boot := "will-" + backend.ID()[:12]
|
||||
status := contracts.Status{Envelope: contracts.Envelope{SchemaVersion: 1, DeviceID: "sim-001"}, BootID: boot, State: "offline", WillConfiguredAt: backend.Timestamp(time.Now())}
|
||||
packet := mqtt.Packet(mqtt.Topic(cfg, "status"), 1, false, status)
|
||||
client := mqtt.New(cfg, store(cfg))
|
||||
if err := client.Start(ctx, []string{"commands"}, &paho.WillMessage{Topic: packet.Topic, Payload: packet.Payload, QoS: 1, Retain: false}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer client.Close()
|
||||
proxy.pause()
|
||||
deadline := time.NewTimer(5 * time.Second)
|
||||
defer deadline.Stop()
|
||||
for {
|
||||
select {
|
||||
case p := <-observer.Incoming:
|
||||
if strings.Contains(string(p.Payload), boot) {
|
||||
if !strings.Contains(string(p.Payload), "will_configured_at") {
|
||||
t.Fatal("Will invents disconnect timestamp")
|
||||
}
|
||||
t.Log("broker emits non-retained Will after actual abrupt TLS connection loss: PASS")
|
||||
return
|
||||
}
|
||||
case <-deadline.C:
|
||||
t.Fatal("Will not observed after abrupt connection loss")
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user