233 lines
6.1 KiB
Go
233 lines
6.1 KiB
Go
package bus_test
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/nats-io/nats.go"
|
|
"github.com/nats-io/nats.go/jetstream"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/staack/the-other-dude/poller/internal/bus"
|
|
"github.com/staack/the-other-dude/poller/internal/testutil"
|
|
)
|
|
|
|
func TestPublisher_PublishStatus_Integration(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("skipping integration test in short mode")
|
|
}
|
|
|
|
natsURL, cleanup := testutil.SetupNATS(t)
|
|
defer cleanup()
|
|
|
|
pub, err := bus.NewPublisher(natsURL)
|
|
require.NoError(t, err)
|
|
defer pub.Close()
|
|
|
|
// Create a direct NATS consumer to receive messages.
|
|
nc, err := nats.Connect(natsURL)
|
|
require.NoError(t, err)
|
|
defer nc.Close()
|
|
|
|
js, err := jetstream.New(nc)
|
|
require.NoError(t, err)
|
|
|
|
ctx := context.Background()
|
|
|
|
// Create a consumer on the DEVICE_EVENTS stream.
|
|
cons, err := js.CreateOrUpdateConsumer(ctx, "DEVICE_EVENTS", jetstream.ConsumerConfig{
|
|
FilterSubject: "device.status.>",
|
|
AckPolicy: jetstream.AckNonePolicy,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// Publish a status event.
|
|
event := bus.DeviceStatusEvent{
|
|
DeviceID: "dev-abc-123",
|
|
TenantID: "tenant-xyz",
|
|
Status: "online",
|
|
LastSeen: time.Now().UTC().Format(time.RFC3339),
|
|
}
|
|
err = pub.PublishStatus(ctx, event)
|
|
require.NoError(t, err)
|
|
|
|
// Consume the message with timeout.
|
|
msgBatch, err := cons.Fetch(1, jetstream.FetchMaxWait(5*time.Second))
|
|
require.NoError(t, err)
|
|
|
|
var received *jetstream.Msg
|
|
for msg := range msgBatch.Messages() {
|
|
received = &msg
|
|
break
|
|
}
|
|
|
|
require.NotNil(t, received, "should receive a message within 5 seconds")
|
|
|
|
var got bus.DeviceStatusEvent
|
|
err = json.Unmarshal((*received).Data(), &got)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, event.DeviceID, got.DeviceID)
|
|
assert.Equal(t, event.TenantID, got.TenantID)
|
|
assert.Equal(t, event.Status, got.Status)
|
|
}
|
|
|
|
func TestPublisher_PublishMetrics_Integration(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("skipping integration test in short mode")
|
|
}
|
|
|
|
natsURL, cleanup := testutil.SetupNATS(t)
|
|
defer cleanup()
|
|
|
|
pub, err := bus.NewPublisher(natsURL)
|
|
require.NoError(t, err)
|
|
defer pub.Close()
|
|
|
|
nc, err := nats.Connect(natsURL)
|
|
require.NoError(t, err)
|
|
defer nc.Close()
|
|
|
|
js, err := jetstream.New(nc)
|
|
require.NoError(t, err)
|
|
|
|
ctx := context.Background()
|
|
|
|
// Create a consumer filtering on metrics subjects.
|
|
cons, err := js.CreateOrUpdateConsumer(ctx, "DEVICE_EVENTS", jetstream.ConsumerConfig{
|
|
FilterSubject: "device.metrics.>",
|
|
AckPolicy: jetstream.AckNonePolicy,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// Publish a metrics event.
|
|
event := bus.DeviceMetricsEvent{
|
|
DeviceID: "dev-metrics-456",
|
|
TenantID: "tenant-xyz",
|
|
CollectedAt: time.Now().UTC().Format(time.RFC3339),
|
|
Type: "health",
|
|
}
|
|
err = pub.PublishMetrics(ctx, event)
|
|
require.NoError(t, err)
|
|
|
|
// Consume the message.
|
|
msgBatch, err := cons.Fetch(1, jetstream.FetchMaxWait(5*time.Second))
|
|
require.NoError(t, err)
|
|
|
|
var received *jetstream.Msg
|
|
for msg := range msgBatch.Messages() {
|
|
received = &msg
|
|
break
|
|
}
|
|
|
|
require.NotNil(t, received, "should receive metrics message within 5 seconds")
|
|
|
|
// Verify the subject includes the type and device_id.
|
|
assert.Equal(t, "device.metrics.health.dev-metrics-456", (*received).Subject())
|
|
|
|
var got bus.DeviceMetricsEvent
|
|
err = json.Unmarshal((*received).Data(), &got)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, event.DeviceID, got.DeviceID)
|
|
assert.Equal(t, event.TenantID, got.TenantID)
|
|
assert.Equal(t, event.Type, got.Type)
|
|
}
|
|
|
|
func TestPublisher_PublishFirmware_Integration(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("skipping integration test in short mode")
|
|
}
|
|
|
|
natsURL, cleanup := testutil.SetupNATS(t)
|
|
defer cleanup()
|
|
|
|
pub, err := bus.NewPublisher(natsURL)
|
|
require.NoError(t, err)
|
|
defer pub.Close()
|
|
|
|
nc, err := nats.Connect(natsURL)
|
|
require.NoError(t, err)
|
|
defer nc.Close()
|
|
|
|
js, err := jetstream.New(nc)
|
|
require.NoError(t, err)
|
|
|
|
ctx := context.Background()
|
|
|
|
cons, err := js.CreateOrUpdateConsumer(ctx, "DEVICE_EVENTS", jetstream.ConsumerConfig{
|
|
FilterSubject: "device.firmware.>",
|
|
AckPolicy: jetstream.AckNonePolicy,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
event := bus.DeviceFirmwareEvent{
|
|
DeviceID: "dev-fw-789",
|
|
TenantID: "tenant-xyz",
|
|
InstalledVersion: "7.15",
|
|
LatestVersion: "7.16",
|
|
Channel: "stable",
|
|
Status: "update_available",
|
|
Architecture: "arm64",
|
|
}
|
|
err = pub.PublishFirmware(ctx, event)
|
|
require.NoError(t, err)
|
|
|
|
msgBatch, err := cons.Fetch(1, jetstream.FetchMaxWait(5*time.Second))
|
|
require.NoError(t, err)
|
|
|
|
var received *jetstream.Msg
|
|
for msg := range msgBatch.Messages() {
|
|
received = &msg
|
|
break
|
|
}
|
|
|
|
require.NotNil(t, received, "should receive firmware message within 5 seconds")
|
|
assert.Equal(t, "device.firmware.dev-fw-789", (*received).Subject())
|
|
|
|
var got bus.DeviceFirmwareEvent
|
|
err = json.Unmarshal((*received).Data(), &got)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, event.DeviceID, got.DeviceID)
|
|
assert.Equal(t, event.InstalledVersion, got.InstalledVersion)
|
|
assert.Equal(t, event.LatestVersion, got.LatestVersion)
|
|
assert.Equal(t, event.Status, got.Status)
|
|
}
|
|
|
|
func TestPublisher_NewPublisher_StreamCreation_Integration(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("skipping integration test in short mode")
|
|
}
|
|
|
|
natsURL, cleanup := testutil.SetupNATS(t)
|
|
defer cleanup()
|
|
|
|
pub, err := bus.NewPublisher(natsURL)
|
|
require.NoError(t, err)
|
|
defer pub.Close()
|
|
|
|
// Verify the DEVICE_EVENTS stream was created with correct config.
|
|
nc, err := nats.Connect(natsURL)
|
|
require.NoError(t, err)
|
|
defer nc.Close()
|
|
|
|
js, err := jetstream.New(nc)
|
|
require.NoError(t, err)
|
|
|
|
ctx := context.Background()
|
|
stream, err := js.Stream(ctx, "DEVICE_EVENTS")
|
|
require.NoError(t, err, "DEVICE_EVENTS stream should exist")
|
|
|
|
info, err := stream.Info(ctx)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, "DEVICE_EVENTS", info.Config.Name)
|
|
assert.Contains(t, info.Config.Subjects, "device.status.>",
|
|
"stream should cover device.status.> subjects")
|
|
assert.Contains(t, info.Config.Subjects, "device.metrics.>",
|
|
"stream should cover device.metrics.> subjects")
|
|
assert.Contains(t, info.Config.Subjects, "device.firmware.>",
|
|
"stream should cover device.firmware.> subjects")
|
|
}
|