Add initial MQTT scrubber service scaffold

This commit is contained in:
2026-03-12 18:12:16 +01:00
parent 957b2c41b3
commit 464f4c3ec4
22 changed files with 4150 additions and 1 deletions
+102
View File
@@ -0,0 +1,102 @@
package parser
import (
"encoding/json"
"os"
"testing"
"time"
"mqqt-scrubber/internal/model"
)
type fixtureCase struct {
Name string `json:"name"`
Topic string `json:"topic"`
Payload string `json:"payload"`
ReceivedAt string `json:"received_at"`
ExpectedMeasurement string `json:"expected_measurement"`
ExpectedTimestamp string `json:"expected_timestamp"`
ExpectedTags map[string]string `json:"expected_tags"`
ExpectedFields map[string]any `json:"expected_fields"`
}
func TestParseTasmotaFixtures(t *testing.T) {
contents, err := os.ReadFile("testdata/tasmota_samples.json")
if err != nil {
t.Fatalf("read fixture file: %v", err)
}
var fixtures []fixtureCase
if err := json.Unmarshal(contents, &fixtures); err != nil {
t.Fatalf("parse fixture file: %v", err)
}
for _, fixture := range fixtures {
t.Run(fixture.Name, func(t *testing.T) {
receivedAt, err := time.Parse(time.RFC3339, fixture.ReceivedAt)
if err != nil {
t.Fatalf("parse receivedAt: %v", err)
}
expectedTimestamp, err := time.Parse(time.RFC3339, fixture.ExpectedTimestamp)
if err != nil {
t.Fatalf("parse expected timestamp: %v", err)
}
records, err := ParseTasmota(model.RawMessage{
Topic: fixture.Topic,
Payload: []byte(fixture.Payload),
ReceivedAt: receivedAt,
})
if err != nil {
t.Fatalf("ParseTasmota returned error: %v", err)
}
if len(records) != 1 {
t.Fatalf("expected 1 record, got %d", len(records))
}
record := records[0]
if record.Measurement != fixture.ExpectedMeasurement {
t.Fatalf("unexpected measurement: got %s want %s", record.Measurement, fixture.ExpectedMeasurement)
}
if !record.Timestamp.Equal(expectedTimestamp) {
t.Fatalf("unexpected timestamp: got %s want %s", record.Timestamp.Format(time.RFC3339), expectedTimestamp.Format(time.RFC3339))
}
for key, value := range fixture.ExpectedTags {
if record.Tags[key] != value {
t.Fatalf("unexpected tag %s: got %q want %q", key, record.Tags[key], value)
}
}
for key, value := range fixture.ExpectedFields {
fieldValue, ok := record.Fields[key]
if !ok {
t.Fatalf("expected field %s to be present", key)
}
if !fieldEquals(fieldValue, value) {
t.Fatalf("unexpected field %s: got %#v want %#v", key, fieldValue, value)
}
}
})
}
}
func fieldEquals(got any, want any) bool {
switch typedWant := want.(type) {
case float64:
typedGot, ok := got.(float64)
return ok && typedGot == typedWant
case string:
typedGot, ok := got.(string)
return ok && typedGot == typedWant
case bool:
typedGot, ok := got.(bool)
return ok && typedGot == typedWant
default:
return false
}
}