check / check (push) Successful in 3m58s
Every reference from a model to the record it belongs to is now json:"-", so the webhook and target models (and the other parent and child pairs in internal/database) can no longer marshal each other in a loop. Preloading maps associations without reading json tags, so it still fills these references. One test preloads a webhook with its targets and entrypoints and a target with its webhook, checks the references are filled, and checks the JSON leaves them out; another builds each other model with its parent set and checks the parent's id is absent from its JSON. Model: opus-5-5
121 lines
3.0 KiB
Go
121 lines
3.0 KiB
Go
package database_test
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"sneak.berlin/go/webhooker/internal/database"
|
|
)
|
|
|
|
// TestPreloadedModelsMarshalWithoutTheirParent pins that a child's
|
|
// reference to the record it belongs to is left out of the JSON, so a
|
|
// webhook and its targets cannot marshal each other in a loop, and that
|
|
// GORM still preloads that reference, since it ignores json tags.
|
|
func TestPreloadedModelsMarshalWithoutTheirParent(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
db := startedTestDB(t)
|
|
|
|
stored := database.Webhook{
|
|
UserID: uuid.New().String(),
|
|
Name: testWebhookName,
|
|
Entrypoints: []database.Entrypoint{{Path: uuid.New().String()}},
|
|
Targets: []database.Target{{
|
|
Name: "log",
|
|
Type: database.TargetTypeLog,
|
|
}},
|
|
}
|
|
require.NoError(t, db.Create(&stored).Error)
|
|
|
|
entrypointID := stored.Entrypoints[0].ID
|
|
targetID := stored.Targets[0].ID
|
|
|
|
var webhook database.Webhook
|
|
|
|
require.NoError(t, db.
|
|
Preload("Entrypoints.Webhook").
|
|
Preload("Targets.Webhook").
|
|
First(&webhook, "id = ?", stored.ID).Error)
|
|
|
|
require.Len(t, webhook.Entrypoints, 1)
|
|
require.Len(t, webhook.Targets, 1)
|
|
assert.Equal(t, stored.ID, webhook.Entrypoints[0].Webhook.ID)
|
|
assert.Equal(t, stored.ID, webhook.Targets[0].Webhook.ID)
|
|
|
|
encoded := marshalModel(t, webhook)
|
|
|
|
assert.Contains(t, encoded, entrypointID)
|
|
assert.Contains(t, encoded, targetID)
|
|
assert.NotContains(t, encoded, `"webhook":`)
|
|
|
|
var target database.Target
|
|
|
|
require.NoError(t, db.
|
|
Preload("Webhook").
|
|
First(&target, "id = ?", targetID).Error)
|
|
|
|
assert.Equal(t, stored.ID, target.Webhook.ID)
|
|
|
|
encoded = marshalModel(t, target)
|
|
|
|
assert.Contains(t, encoded, stored.ID)
|
|
assert.NotContains(t, encoded, `"webhook":`)
|
|
}
|
|
|
|
// TestModelsMarshalWithoutTheirParent covers the other references to a
|
|
// parent: each model is built with its parent set, and the parent's id
|
|
// must not appear in the JSON.
|
|
func TestModelsMarshalWithoutTheirParent(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
parent := database.BaseModel{ID: uuid.New().String()}
|
|
|
|
cases := []struct {
|
|
name string
|
|
model any
|
|
}{
|
|
{
|
|
name: "Webhook.User",
|
|
model: database.Webhook{User: database.User{BaseModel: parent}},
|
|
},
|
|
{
|
|
name: "APIKey.User",
|
|
model: database.APIKey{User: database.User{BaseModel: parent}},
|
|
},
|
|
{
|
|
name: "Delivery.Event",
|
|
model: database.Delivery{Event: database.Event{BaseModel: parent}},
|
|
},
|
|
{
|
|
name: "Delivery.Target",
|
|
model: database.Delivery{Target: database.Target{BaseModel: parent}},
|
|
},
|
|
{
|
|
name: "DeliveryResult.Delivery",
|
|
model: database.DeliveryResult{
|
|
Delivery: database.Delivery{BaseModel: parent},
|
|
},
|
|
},
|
|
{
|
|
name: "Event.Webhook",
|
|
model: database.Event{Webhook: database.Webhook{BaseModel: parent}},
|
|
},
|
|
{
|
|
name: "Event.Entrypoint",
|
|
model: database.Event{
|
|
Entrypoint: database.Entrypoint{BaseModel: parent},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
assert.NotContains(t, marshalModel(t, tc.model), parent.ID)
|
|
})
|
|
}
|
|
}
|