mirror of
https://github.com/MeshCore-Beacon/beacon-server.git
synced 2026-09-01 16:48:19 +00:00
first db <> api mapping add filter to test coverage action to ignore generated code like sqlc and swagger docs
182 lines
4.4 KiB
Go
182 lines
4.4 KiB
Go
// Copyright 2026 Beacon Contributors
|
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
package db
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
"time"
|
|
|
|
sqlc "github.com/MeshCore-Beacon/beacon-server/db/sqlc"
|
|
mockdb "github.com/MeshCore-Beacon/beacon-server/db/sqlc/mock"
|
|
"github.com/google/uuid"
|
|
"github.com/jackc/pgx/v5/pgtype"
|
|
"go.uber.org/mock/gomock"
|
|
)
|
|
|
|
func TestNullableUUID_Zero(t *testing.T) {
|
|
if nullableUUID(uuid.UUID{}) != nil {
|
|
t.Error("expected nil for zero UUID")
|
|
}
|
|
}
|
|
|
|
func TestNullableUUID_NonZero(t *testing.T) {
|
|
id := uuid.New()
|
|
result := nullableUUID(id)
|
|
if result == nil {
|
|
t.Fatal("expected non-nil for non-zero UUID")
|
|
}
|
|
if *result != id {
|
|
t.Errorf("expected %s, got %s", id, *result)
|
|
}
|
|
}
|
|
|
|
func TestTristate_Nil(t *testing.T) {
|
|
if tristate(nil) != "any" {
|
|
t.Error("expected \"any\" for nil")
|
|
}
|
|
}
|
|
|
|
func TestTristate_True(t *testing.T) {
|
|
b := true
|
|
if tristate(&b) != "true" {
|
|
t.Error("expected \"true\" for true")
|
|
}
|
|
}
|
|
|
|
func TestTristate_False(t *testing.T) {
|
|
b := false
|
|
if tristate(&b) != "false" {
|
|
t.Error("expected \"false\" for false")
|
|
}
|
|
}
|
|
|
|
func TestToChannelMessage(t *testing.T) {
|
|
senderName := "Alice"
|
|
content := "hello"
|
|
channelHash := []byte{0xab}
|
|
sentAt := pgtype.Timestamptz{Time: time.UnixMilli(1700000000000), Valid: true}
|
|
|
|
msg := toChannelMessage(42, "deadbeef", channelHash, &senderName, &content, sentAt, 7)
|
|
|
|
if msg.ID != 42 {
|
|
t.Errorf("expected ID 42, got %d", msg.ID)
|
|
}
|
|
if msg.PacketHash != "deadbeef" {
|
|
t.Errorf("expected PacketHash deadbeef, got %s", msg.PacketHash)
|
|
}
|
|
if msg.ChannelHash != "ab" {
|
|
t.Errorf("expected ChannelHash ab, got %s", msg.ChannelHash)
|
|
}
|
|
if msg.SenderName != "Alice" {
|
|
t.Errorf("expected SenderName Alice, got %s", msg.SenderName)
|
|
}
|
|
if msg.Content != "hello" {
|
|
t.Errorf("expected Content hello, got %s", msg.Content)
|
|
}
|
|
if msg.SentAt != 1700000000000 {
|
|
t.Errorf("expected SentAt 1700000000000, got %d", msg.SentAt)
|
|
}
|
|
if msg.ObservationCount != 7 {
|
|
t.Errorf("expected ObservationCount 7, got %d", msg.ObservationCount)
|
|
}
|
|
}
|
|
|
|
func TestToChannelMessage_NilFields(t *testing.T) {
|
|
sentAt := pgtype.Timestamptz{Time: time.UnixMilli(0), Valid: true}
|
|
msg := toChannelMessage(1, "abc", []byte{0x01}, nil, nil, sentAt, 0)
|
|
if msg.SenderName != "" {
|
|
t.Errorf("expected empty SenderName, got %s", msg.SenderName)
|
|
}
|
|
if msg.Content != "" {
|
|
t.Errorf("expected empty Content, got %s", msg.Content)
|
|
}
|
|
}
|
|
|
|
func TestResolvePathHashes_Empty(t *testing.T) {
|
|
ctrl := gomock.NewController(t)
|
|
mock := mockdb.NewMockQuerier(ctrl)
|
|
// no EXPECT — sqlc should never be called
|
|
store := &Store{q: mock}
|
|
|
|
result, err := store.ResolvePathHashes(context.Background(), "YVR", nil)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if result != nil {
|
|
t.Errorf("expected nil, got %v", result)
|
|
}
|
|
}
|
|
|
|
func TestResolvePathHashes_DBError(t *testing.T) {
|
|
ctrl := gomock.NewController(t)
|
|
mock := mockdb.NewMockQuerier(ctrl)
|
|
|
|
hashes := [][]byte{{0x01, 0x02}}
|
|
mock.EXPECT().
|
|
ResolvePathHashes(gomock.Any(), sqlc.ResolvePathHashesParams{
|
|
Iata: "YVR",
|
|
Column2: hashes,
|
|
}).
|
|
Return(nil, errors.New("db error"))
|
|
|
|
store := &Store{q: mock}
|
|
result, err := store.ResolvePathHashes(context.Background(), "YVR", hashes)
|
|
if err == nil {
|
|
t.Fatal("expected error, got nil")
|
|
}
|
|
if result != nil {
|
|
t.Errorf("expected nil result on error, got %v", result)
|
|
}
|
|
}
|
|
|
|
func TestResolvePathHashes_Mapping(t *testing.T) {
|
|
ctrl := gomock.NewController(t)
|
|
mock := mockdb.NewMockQuerier(ctrl)
|
|
|
|
nodeID := uuid.MustParse("00000000-0000-0000-0000-000000000001")
|
|
name := "test-node"
|
|
lat := 49.1967
|
|
lon := -123.1815
|
|
pubkey := []byte{0xde, 0xad}
|
|
hashes := [][]byte{{0xab, 0xcd}}
|
|
|
|
mock.EXPECT().
|
|
ResolvePathHashes(gomock.Any(), sqlc.ResolvePathHashesParams{
|
|
Iata: "YVR",
|
|
Column2: hashes,
|
|
}).
|
|
Return([]sqlc.ResolvePathHashesRow{
|
|
{
|
|
Hash: []byte{0xab, 0xcd},
|
|
NodeID: nodeID,
|
|
Name: &name,
|
|
Latitude: &lat,
|
|
Longitude: &lon,
|
|
PublicKey: pubkey,
|
|
},
|
|
}, nil)
|
|
|
|
store := &Store{q: mock}
|
|
result, err := store.ResolvePathHashes(context.Background(), "YVR", hashes)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
|
|
entries, ok := result["abcd"]
|
|
if !ok {
|
|
t.Fatal("expected key abcd in result")
|
|
}
|
|
if len(entries) != 1 {
|
|
t.Fatalf("expected 1 entry, got %d", len(entries))
|
|
}
|
|
if entries[0].NodeID != nodeID {
|
|
t.Errorf("expected NodeID %s, got %s", nodeID, entries[0].NodeID)
|
|
}
|
|
if entries[0].Name != &name {
|
|
t.Errorf("expected Name %s, got %v", name, entries[0].Name)
|
|
}
|
|
}
|