// Copyright © 2023 Ory Corp // SPDX-License-Identifier: Apache-2.0 package errorx import ( "context" "encoding/json" "testing" "time" "github.com/ory/kratos/pkg/testhelpers" "github.com/ory/kratos/persistence" "github.com/ory/x/sqlcon" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/tidwall/gjson" "github.com/ory/herodot" "github.com/ory/kratos/x" ) func TestPersister(ctx context.Context, p persistence.Persister) func(t *testing.T) { toJSON := func(t *testing.T, in interface{}) string { out, err := json.Marshal(in) require.NoError(t, err) return string(out) } return func(t *testing.T) { _, p := testhelpers.NewNetworkUnlessExisting(t, ctx, p) t.Run("case=not found", func(t *testing.T) { _, err := p.ReadErrorContainer(ctx, x.NewUUID()) require.Error(t, err) }) t.Run("case=en- and decode properly", func(t *testing.T) { actualID, err := p.CreateErrorContainer(ctx, "nosurf", herodot.ErrNotFound().WithReason("foobar")) require.NoError(t, err) actual, err := p.ReadErrorContainer(ctx, actualID) require.NoError(t, err) assert.JSONEq(t, `{"code":404,"status":"Not Found","reason":"foobar","message":"The requested resource could not be found"}`, gjson.Get(toJSON(t, actual), "error").String(), toJSON(t, actual)) }) t.Run("case=clear", func(t *testing.T) { actualID, err := p.CreateErrorContainer(ctx, "nosurf", herodot.ErrNotFound().WithReason("foobar")) require.NoError(t, err) _, err = p.ReadErrorContainer(ctx, actualID) require.NoError(t, err) // The row must age past the one-second cutoff before ClearErrorContainers // removes it, and ReadErrorContainer refreshes seen_at on every read, so // polling would keep resetting the age. Wait once instead. The extra 0.5s // covers MySQL's one-second timestamp resolution. time.Sleep(time.Second + time.Millisecond*500) require.NoError(t, p.ClearErrorContainers(ctx, time.Second, false)) got, err := p.ReadErrorContainer(ctx, actualID) require.Error(t, err, "%+v", got) }) t.Run("case=network", func(t *testing.T) { t.Run("can not read error from another network", func(t *testing.T) { created, err := p.CreateErrorContainer(ctx, "nosurf", herodot.ErrNotFound().WithReason("foobar")) require.NoError(t, err) _, other := testhelpers.NewNetwork(t, ctx, p) _, err = other.ReadErrorContainer(ctx, created) require.ErrorIs(t, err, sqlcon.ErrNoRows()) t.Run("can not clear another network", func(t *testing.T) { _, other := testhelpers.NewNetwork(t, ctx, p) require.NoError(t, other.ClearErrorContainers(ctx, time.Second, true)) c, err := p.ReadErrorContainer(ctx, created) require.NoError(t, err) assert.Contains(t, string(c.Errors), "foobar") }) }) }) } }