check / check (push) In progress
Every reference from a model to the record it belongs to (a target's or entrypoint's webhook, a webhook's or API key's user, an event's webhook and entrypoint, a delivery's event and target, a delivery result's delivery) is now tagged json:"-", so a preloaded model can be marshalled without the encoder recursing between parent and child. References to child records stay. Tests marshal each of the nine references set, preloaded where it matters, and check the parent's id is absent, so deleting or restoring any one tag fails a test; preloading still fills each reference. Model: opus-5-5
127 lines
3.3 KiB
Go
127 lines
3.3 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)
|
|
|
|
// Each child holds the parent's id as its webhookId, so the parent
|
|
// is looked for by its own id field.
|
|
parentIDField := `"id":"` + stored.ID + `"`
|
|
|
|
assert.NotContains(t, marshalModel(t, webhook.Entrypoints[0]), parentIDField)
|
|
assert.NotContains(t, marshalModel(t, webhook.Targets[0]), parentIDField)
|
|
|
|
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, parentIDField)
|
|
}
|
|
|
|
// 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)
|
|
})
|
|
}
|
|
}
|