Files
cactoandClaude Sonnet 5 938700cf86 Implement ingest-service: MQTT -> ClickHouse (batched) + RabbitMQ event
Subscribes to devices/+/telemetry, validates payloads, buffers writes into
ClickHouse (flush on size or interval), and emits a per-reading event on
RabbitMQ for rule-engine-service to consume later. Adds the initial Postgres
and ClickHouse schema migrations, a Dockerfile, and wires the service into
docker-compose. Verified end-to-end via docker compose + mosquitto_pub: row
lands in ClickHouse and the event reaches the telemetry.new_reading queue.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-26 16:52:45 +05:00

75 lines
1.9 KiB
Go

package telemetry
import (
"testing"
"time"
)
func TestParseReading_Valid(t *testing.T) {
receivedAt := time.Date(2026, 7, 26, 12, 0, 5, 0, time.UTC)
raw := []byte(`{
"device_id": "esp32-abc123",
"zone_id": "growbox-1",
"sensor_type": "temperature",
"value": 24.5,
"timestamp": "2026-07-26T12:00:00Z"
}`)
got, err := ParseReading(raw, receivedAt)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
want := Reading{
DeviceID: "esp32-abc123",
ZoneID: "growbox-1",
SensorType: "temperature",
Value: 24.5,
RecordedAt: time.Date(2026, 7, 26, 12, 0, 0, 0, time.UTC),
ReceivedAt: receivedAt,
}
if got != want {
t.Fatalf("got %+v, want %+v", got, want)
}
}
func TestParseReading_Invalid(t *testing.T) {
receivedAt := time.Now()
cases := map[string]string{
"malformed json": `{not json`,
"missing device_id": `{
"zone_id": "growbox-1", "sensor_type": "temperature",
"value": 1, "timestamp": "2026-07-26T12:00:00Z"
}`,
"missing zone_id": `{
"device_id": "esp32-1", "sensor_type": "temperature",
"value": 1, "timestamp": "2026-07-26T12:00:00Z"
}`,
"missing sensor_type": `{
"device_id": "esp32-1", "zone_id": "growbox-1",
"value": 1, "timestamp": "2026-07-26T12:00:00Z"
}`,
"missing timestamp": `{
"device_id": "esp32-1", "zone_id": "growbox-1",
"sensor_type": "temperature", "value": 1
}`,
"invalid timestamp format": `{
"device_id": "esp32-1", "zone_id": "growbox-1",
"sensor_type": "temperature", "value": 1, "timestamp": "not-a-date"
}`,
"value wrong type": `{
"device_id": "esp32-1", "zone_id": "growbox-1",
"sensor_type": "temperature", "value": "not-a-number", "timestamp": "2026-07-26T12:00:00Z"
}`,
}
for name, raw := range cases {
t.Run(name, func(t *testing.T) {
if _, err := ParseReading([]byte(raw), receivedAt); err == nil {
t.Fatalf("expected error, got nil")
}
})
}
}