server/internal/handlers/entries_create_test.go
Rama main · réplica de lectura del repositorio original.
package handlers_test
import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"time"
"blackbox/server/internal/handlers"
"blackbox/shared/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gorm.io/gorm"
)
func TestCreateEntry(t *testing.T) {
t.Parallel()
tests := []struct {
name string
setup func(t *testing.T, database *gorm.DB)
body string
wantStatus int
checkTimestamp bool
assertEntry func(t *testing.T, entry types.Entry)
}{
{
name: "creates manual entry with explicit timestamp and services",
body: `{"title":"Nightly backup completed","note":"manual run","services":["postgres","storage"],"timestamp":"2026-04-02T10:15:30Z"}`,
wantStatus: http.StatusCreated,
assertEntry: func(t *testing.T, entry types.Entry) {
t.Helper()
assert.Equal(t, "api", entry.NodeName)
assert.Equal(t, "api", entry.Source)
assert.Equal(t, "manual", entry.Event)
assert.Equal(t, "postgres", entry.Service)
assert.Equal(t, "Nightly backup completed", entry.Content)
assert.Equal(t, time.Date(2026, 4, 2, 10, 15, 30, 0, time.UTC), entry.Timestamp)
var meta map[string]interface{}
require.NoError(t, json.Unmarshal([]byte(entry.Metadata), &meta))
assert.Equal(t, "manual run", meta["note"])
assert.Equal(t, []interface{}{"postgres", "storage"}, meta["services"])
},
},
{
name: "normalizes service names before saving",
body: `{"title":"Failover completed","note":"manual run","services":[" Postgres "],"timestamp":"2026-04-02T10:15:30Z"}`,
wantStatus: http.StatusCreated,
assertEntry: func(t *testing.T, entry types.Entry) {
t.Helper()
assert.Equal(t, "postgres", entry.Service)
assert.Equal(t, "Failover completed", entry.Content)
assert.Equal(t, "api", entry.NodeName)
var meta map[string]interface{}
require.NoError(t, json.Unmarshal([]byte(entry.Metadata), &meta))
assert.Equal(t, []interface{}{"postgres"}, meta["services"])
assert.Equal(t, "manual run", meta["note"])
},
},
{
name: "ignores blank normalized services",
body: `{"title":"Failover completed","note":"manual run","services":[" "," POSTGRES "],"timestamp":"2026-04-02T10:15:30Z"}`,
wantStatus: http.StatusCreated,
assertEntry: func(t *testing.T, entry types.Entry) {
t.Helper()
assert.Equal(t, "postgres", entry.Service)
var meta map[string]interface{}
require.NoError(t, json.Unmarshal([]byte(entry.Metadata), &meta))
assert.Equal(t, []interface{}{"postgres"}, meta["services"])
},
},
{
name: "uses server time when timestamp omitted",
body: `{"title":"Ad hoc check","note":""}`,
wantStatus: http.StatusCreated,
checkTimestamp: true,
assertEntry: func(t *testing.T, entry types.Entry) {
t.Helper()
assert.Equal(t, "", entry.Service)
var meta map[string]interface{}
require.NoError(t, json.Unmarshal([]byte(entry.Metadata), &meta))
assert.Equal(t, "", meta["note"])
assert.Equal(t, []interface{}{}, meta["services"])
},
},
{
name: "rejects invalid timestamp",
body: `{"title":"Ad hoc check","note":"","timestamp":"not-a-time"}`,
wantStatus: http.StatusBadRequest,
assertEntry: func(t *testing.T, entry types.Entry) {
t.Helper()
},
},
{
name: "rejects missing title",
body: `{"note":"missing title"}`,
wantStatus: http.StatusBadRequest,
assertEntry: func(t *testing.T, entry types.Entry) {
t.Helper()
},
},
{
name: "rejects whitespace-only title",
body: `{"title":" ","note":"missing title"}`,
wantStatus: http.StatusBadRequest,
assertEntry: func(t *testing.T, entry types.Entry) {
t.Helper()
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
database := newTestDB(t)
if tt.setup != nil {
tt.setup(t, database)
}
req := httptest.NewRequest(http.MethodPost, "/api/entries", bytes.NewBufferString(tt.body))
req.Header.Set("Content-Type", "application/json")
rr := httptest.NewRecorder()
before := time.Now().UTC()
handlers.CreateEntry(database, nil, testIncidentChannel(t), nil)(rr, req)
after := time.Now().UTC()
require.Equal(t, tt.wantStatus, rr.Code, rr.Body.String())
var entries []types.Entry
require.NoError(t, database.Find(&entries).Error)
if tt.wantStatus != http.StatusCreated {
assert.Empty(t, entries)
return
}
require.Len(t, entries, 1)
var responseEntry types.Entry
require.NoError(t, json.Unmarshal(rr.Body.Bytes(), &responseEntry))
assert.Equal(t, entries[0].ID, responseEntry.ID)
if tt.checkTimestamp {
assert.True(t, entries[0].Timestamp.After(before) || entries[0].Timestamp.Equal(before))
assert.True(t, entries[0].Timestamp.Before(after) || entries[0].Timestamp.Equal(after))
}
tt.assertEntry(t, entries[0])
})
}
}