Ctrl K
ComunidadGuías…

server/internal/handlers/entries_create_test.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
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])
		})
	}
}