126 lines
3.6 KiB
Go
126 lines
3.6 KiB
Go
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 TestParseTasmotaInLocationUsesConfiguredTimezoneForTimezoneLessTime(t *testing.T) {
|
|
location := time.FixedZone("CET", 3600)
|
|
receivedAt := time.Date(2026, time.March, 16, 11, 55, 30, 0, time.UTC)
|
|
|
|
records, err := ParseTasmotaInLocation(model.RawMessage{
|
|
Topic: "tele/tasmota_67850B/SENSOR",
|
|
Payload: []byte(`{"Time":"2026-03-16T11:55:29","ENERGY":{"Power":9}}`),
|
|
ReceivedAt: receivedAt,
|
|
}, location)
|
|
if err != nil {
|
|
t.Fatalf("ParseTasmotaInLocation returned error: %v", err)
|
|
}
|
|
|
|
if len(records) != 1 {
|
|
t.Fatalf("expected 1 record, got %d", len(records))
|
|
}
|
|
|
|
want := time.Date(2026, time.March, 16, 10, 55, 29, 0, time.UTC)
|
|
if !records[0].Timestamp.Equal(want) {
|
|
t.Fatalf("unexpected timestamp: got %s want %s", records[0].Timestamp.Format(time.RFC3339), want.Format(time.RFC3339))
|
|
}
|
|
}
|
|
|
|
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
|
|
}
|
|
}
|