Files
lambdaiot-core/internal/handler/handlers_integration_test.go

203 lines
5.6 KiB
Go

package handler
import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"time"
"github.com/DATA-DOG/go-sqlmock"
"github.com/gin-gonic/gin"
)
// helper to build gin engine with given handler without auth for focused handler tests
func newTestRouter(h *Handler, register func(*gin.Engine)) *gin.Engine {
gin.SetMode(gin.TestMode)
r := gin.New()
register(r)
return r
}
// helper to set up sqlmock-backed handler
func newMockHandler(t *testing.T) (*Handler, sqlmock.Sqlmock, func()) {
t.Helper()
db, mock, err := sqlmock.New()
if err != nil {
t.Fatalf("sqlmock: %v", err)
}
h := &Handler{DB: db, JWTSecret: "secret"}
cleanup := func() { db.Close() }
return h, mock, cleanup
}
func TestCreateSensor(t *testing.T) {
h, mock, cleanup := newMockHandler(t)
defer cleanup()
mock.ExpectExec("INSERT INTO sensors").
WithArgs(sqlmock.AnyArg(), sqlmock.AnyArg(), "temp", "bool", 1).
WillReturnResult(sqlmock.NewResult(0, 1))
r := newTestRouter(h, func(r *gin.Engine) {
r.POST("/sensors", h.CreateSensor)
})
body := map[string]interface{}{
"device_id": "11111111-1111-1111-1111-111111111111",
"name": "temp",
"type": "bool",
"data_type_id": 1,
}
buf, _ := json.Marshal(body)
req := httptest.NewRequest(http.MethodPost, "/sensors", bytes.NewReader(buf))
req.Header.Set("Content-Type", "application/json")
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
if w.Code != http.StatusCreated {
t.Fatalf("expected 201 got %d, body=%s", w.Code, w.Body.String())
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatalf("expectations: %v", err)
}
}
func TestGetSensors(t *testing.T) {
h, mock, cleanup := newMockHandler(t)
defer cleanup()
rows := sqlmock.NewRows([]string{"id", "device_id", "name", "type", "data_type_id", "created_at", "updated_at"}).
AddRow("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb", "temp", "bool", 1, time.Now(), time.Now())
mock.ExpectQuery(`SELECT BIN_TO_UUID\(id\)`).WillReturnRows(rows)
r := newTestRouter(h, func(r *gin.Engine) {
r.GET("/sensors", h.GetSensors)
})
req := httptest.NewRequest(http.MethodGet, "/sensors", nil)
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
if w.Code != http.StatusOK {
t.Fatalf("expected 200 got %d, body=%s", w.Code, w.Body.String())
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatalf("expectations: %v", err)
}
}
func TestCreateActor(t *testing.T) {
h, mock, cleanup := newMockHandler(t)
defer cleanup()
mock.ExpectExec("INSERT INTO actors").
WithArgs(sqlmock.AnyArg(), sqlmock.AnyArg(), "led", "switch", 1).
WillReturnResult(sqlmock.NewResult(0, 1))
r := newTestRouter(h, func(r *gin.Engine) {
r.POST("/actors", h.CreateActor)
})
body := map[string]interface{}{
"device_id": "11111111-1111-1111-1111-111111111111",
"name": "led",
"type": "switch",
"data_type_id": 1,
}
buf, _ := json.Marshal(body)
req := httptest.NewRequest(http.MethodPost, "/actors", bytes.NewReader(buf))
req.Header.Set("Content-Type", "application/json")
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
if w.Code != http.StatusCreated {
t.Fatalf("expected 201 got %d, body=%s", w.Code, w.Body.String())
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatalf("expectations: %v", err)
}
}
func TestGetActors(t *testing.T) {
h, mock, cleanup := newMockHandler(t)
defer cleanup()
rows := sqlmock.NewRows([]string{"id", "device_id", "name", "type", "data_type_id", "created_at", "updated_at"}).
AddRow("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb", "led", "switch", 1, time.Now(), time.Now())
mock.ExpectQuery(`SELECT BIN_TO_UUID\(id\).*FROM actors`).WillReturnRows(rows)
r := newTestRouter(h, func(r *gin.Engine) {
r.GET("/actors", h.GetActors)
})
req := httptest.NewRequest(http.MethodGet, "/actors", nil)
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
if w.Code != http.StatusOK {
t.Fatalf("expected 200 got %d, body=%s", w.Code, w.Body.String())
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatalf("expectations: %v", err)
}
}
func TestCreateSensorReading(t *testing.T) {
h, mock, cleanup := newMockHandler(t)
defer cleanup()
mock.ExpectExec("INSERT INTO sensor_readings").
WithArgs(sqlmock.AnyArg(), 42.0, sqlmock.AnyArg()).
WillReturnResult(sqlmock.NewResult(10, 1))
r := newTestRouter(h, func(r *gin.Engine) {
r.POST("/sensor-readings", h.CreateSensorReading)
})
body := map[string]interface{}{
"sensor_id": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
"value": 42.0,
}
buf, _ := json.Marshal(body)
req := httptest.NewRequest(http.MethodPost, "/sensor-readings", bytes.NewReader(buf))
req.Header.Set("Content-Type", "application/json")
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
if w.Code != http.StatusCreated {
t.Fatalf("expected 201 got %d, body=%s", w.Code, w.Body.String())
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatalf("expectations: %v", err)
}
}
func TestGetSensorReadings(t *testing.T) {
h, mock, cleanup := newMockHandler(t)
defer cleanup()
rows := sqlmock.NewRows([]string{"id", "sensor_id", "value", "value_at"}).
AddRow(int64(1), "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", 1.23, time.Now())
mock.ExpectQuery(`SELECT id, BIN_TO_UUID\(sensor_id\)`).WillReturnRows(rows)
r := newTestRouter(h, func(r *gin.Engine) {
r.GET("/sensor-readings", h.GetSensorReadings)
})
req := httptest.NewRequest(http.MethodGet, "/sensor-readings", nil)
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
if w.Code != http.StatusOK {
t.Fatalf("expected 200 got %d, body=%s", w.Code, w.Body.String())
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatalf("expectations: %v", err)
}
}