Some checks failed
CI / Run tests and lints (push) Failing after 29s
CI / Build CLI docs (push) Has been skipped
CI / Run Playwright end-to-end tests (mysql) (push) Failing after 3s
CI / Run Playwright end-to-end tests (postgres) (push) Failing after 2s
CI / Run Playwright end-to-end tests (sqlite) (push) Failing after 3s
CodeQL / Analyze (go) (push) Failing after 4s
CodeQL / Analyze (javascript) (push) Failing after 3s
Docker Image Scanners / scanners (push) Failing after 4s
Synchronize Issue Labels / Synchronize Issue Labels (push) Has been skipped
CI / Run end-to-end tests (postgres) (push) Failing after 19s
CI / Run end-to-end tests (sqlite) (push) Failing after 2s
CI / Run Playwright end-to-end tests (cockroach) (push) Failing after 2s
CI / Draft newsletter (push) Has been skipped
CI / Generate release (push) Has been skipped
CI / Pending approval Slack notification (push) Has been skipped
CI / Send newsletter (push) Has been skipped
271 lines
9.2 KiB
Go
271 lines
9.2 KiB
Go
// Copyright © 2025 Ory Corp
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package events_test
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
|
|
"github.com/gofrs/uuid"
|
|
"github.com/stretchr/testify/assert"
|
|
"go.opentelemetry.io/otel/attribute"
|
|
"go.opentelemetry.io/otel/trace"
|
|
|
|
"github.com/ory/kratos/identity"
|
|
"github.com/ory/kratos/x"
|
|
"github.com/ory/kratos/x/events"
|
|
"github.com/ory/x/otelx/semconv"
|
|
)
|
|
|
|
func TestNewJsonnetMappingFailed(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
err error
|
|
jsonnetInput []byte
|
|
jsonnetOutput string
|
|
provider string
|
|
method identity.CredentialsType
|
|
expectedAttrs []attribute.KeyValue
|
|
}{
|
|
{
|
|
name: "With all attributes",
|
|
err: errors.New("test error"),
|
|
jsonnetInput: []byte(`{"key": "PII value"}`),
|
|
jsonnetOutput: `{"key": 123}`,
|
|
provider: "test-provider",
|
|
method: identity.CredentialsTypeOIDC,
|
|
expectedAttrs: []attribute.KeyValue{
|
|
attribute.String("SelfServiceSSOProviderUsed", "test-provider"),
|
|
attribute.String("SelfServiceMethodUsed", "oidc"),
|
|
attribute.String("ErrorReason", "test error"),
|
|
attribute.String("JsonnetInput", `{
|
|
"key": "string"
|
|
}`),
|
|
attribute.String("JsonnetOutput", `{
|
|
"key": "number"
|
|
}`),
|
|
},
|
|
},
|
|
{
|
|
name: "Without JsonnetOutput",
|
|
err: errors.New("another error"),
|
|
jsonnetInput: []byte(`{"key": "PII value"}`),
|
|
jsonnetOutput: "",
|
|
provider: "another-provider",
|
|
method: identity.CredentialsTypeSAML,
|
|
expectedAttrs: []attribute.KeyValue{
|
|
attribute.String("SelfServiceSSOProviderUsed", "another-provider"),
|
|
attribute.String("SelfServiceMethodUsed", "saml"),
|
|
attribute.String("ErrorReason", "another error"),
|
|
attribute.String("JsonnetInput", `{
|
|
"key": "string"
|
|
}`),
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
ctx := t.Context()
|
|
eventName, opts := events.NewJsonnetMappingFailed(ctx, tt.err, tt.jsonnetInput, tt.jsonnetOutput, tt.provider, tt.method.String())
|
|
|
|
assert.Equal(t, events.JsonnetMappingFailed.String(), eventName)
|
|
|
|
eventConfig := trace.NewEventConfig(opts)
|
|
assert.ElementsMatch(t, tt.expectedAttrs, eventConfig.Attributes())
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNewLoginFailed(t *testing.T) {
|
|
ctx := t.Context()
|
|
flowID := uuid.Must(uuid.NewV4())
|
|
identityID := uuid.Must(uuid.NewV4())
|
|
baseErr := errors.New("login failed")
|
|
|
|
t.Run("case=without identity ID", func(t *testing.T) {
|
|
eventName, opts := events.NewLoginFailed(ctx, flowID, "browser", "password", "aal1", false, baseErr)
|
|
|
|
assert.Equal(t, events.LoginFailed.String(), eventName)
|
|
|
|
eventConfig := trace.NewEventConfig(opts)
|
|
attrs := eventConfig.Attributes()
|
|
|
|
// Should not contain IdentityID attribute
|
|
for _, attr := range attrs {
|
|
assert.NotEqual(t, "IdentityID", string(attr.Key))
|
|
}
|
|
|
|
// Should contain other attributes
|
|
assert.Contains(t, attrs, attribute.String("SelfServiceFlowType", "browser"))
|
|
assert.Contains(t, attrs, attribute.String("LoginRequestedAAL", "aal1"))
|
|
assert.Contains(t, attrs, attribute.Bool("LoginRequestedPrivilegedSession", false))
|
|
assert.Contains(t, attrs, attribute.String("ErrorReason", "login failed"))
|
|
assert.Contains(t, attrs, attribute.String("SelfServiceMethodUsed", "password"))
|
|
})
|
|
|
|
t.Run("case=with identity ID", func(t *testing.T) {
|
|
wrappedErr := x.WrapWithIdentityIDError(baseErr, identityID)
|
|
eventName, opts := events.NewLoginFailed(ctx, flowID, "browser", "password", "aal1", false, wrappedErr)
|
|
|
|
assert.Equal(t, events.LoginFailed.String(), eventName)
|
|
|
|
eventConfig := trace.NewEventConfig(opts)
|
|
attrs := eventConfig.Attributes()
|
|
|
|
assert.Contains(t, attrs, attribute.String("IdentityID", identityID.String()))
|
|
assert.Contains(t, attrs, attribute.String("SelfServiceFlowType", "browser"))
|
|
assert.Contains(t, attrs, attribute.String("ErrorReason", "login failed"))
|
|
})
|
|
}
|
|
|
|
func TestNewRecoveryFailed(t *testing.T) {
|
|
ctx := t.Context()
|
|
flowID := uuid.Must(uuid.NewV4())
|
|
identityID := uuid.Must(uuid.NewV4())
|
|
baseErr := errors.New("recovery failed")
|
|
|
|
t.Run("case=without identity ID", func(t *testing.T) {
|
|
eventName, opts := events.NewRecoveryFailed(ctx, flowID, "browser", "code", baseErr)
|
|
|
|
assert.Equal(t, events.RecoveryFailed.String(), eventName)
|
|
|
|
eventConfig := trace.NewEventConfig(opts)
|
|
attrs := eventConfig.Attributes()
|
|
|
|
for _, attr := range attrs {
|
|
assert.NotEqual(t, "IdentityID", string(attr.Key))
|
|
}
|
|
|
|
assert.Contains(t, attrs, attribute.String("SelfServiceFlowType", "browser"))
|
|
assert.Contains(t, attrs, attribute.String("SelfServiceMethodUsed", "code"))
|
|
})
|
|
|
|
t.Run("case=with identity ID", func(t *testing.T) {
|
|
wrappedErr := x.WrapWithIdentityIDError(baseErr, identityID)
|
|
eventName, opts := events.NewRecoveryFailed(ctx, flowID, "browser", "link", wrappedErr)
|
|
|
|
assert.Equal(t, events.RecoveryFailed.String(), eventName)
|
|
|
|
eventConfig := trace.NewEventConfig(opts)
|
|
attrs := eventConfig.Attributes()
|
|
|
|
assert.Contains(t, attrs, attribute.String("IdentityID", identityID.String()))
|
|
assert.Contains(t, attrs, attribute.String("SelfServiceFlowType", "browser"))
|
|
assert.Contains(t, attrs, attribute.String("SelfServiceMethodUsed", "link"))
|
|
})
|
|
}
|
|
|
|
func TestNewSettingsFailed(t *testing.T) {
|
|
ctx := t.Context()
|
|
flowID := uuid.Must(uuid.NewV4())
|
|
identityID := uuid.Must(uuid.NewV4())
|
|
baseErr := errors.New("settings failed")
|
|
|
|
t.Run("case=without identity ID", func(t *testing.T) {
|
|
eventName, opts := events.NewSettingsFailed(ctx, flowID, "browser", "profile", baseErr)
|
|
|
|
assert.Equal(t, events.SettingsFailed.String(), eventName)
|
|
|
|
eventConfig := trace.NewEventConfig(opts)
|
|
attrs := eventConfig.Attributes()
|
|
|
|
for _, attr := range attrs {
|
|
assert.NotEqual(t, "IdentityID", string(attr.Key))
|
|
}
|
|
|
|
assert.Contains(t, attrs, attribute.String("SelfServiceFlowType", "browser"))
|
|
assert.Contains(t, attrs, attribute.String("SelfServiceMethodUsed", "profile"))
|
|
})
|
|
|
|
t.Run("case=with identity ID", func(t *testing.T) {
|
|
wrappedErr := x.WrapWithIdentityIDError(baseErr, identityID)
|
|
eventName, opts := events.NewSettingsFailed(ctx, flowID, "browser", "password", wrappedErr)
|
|
|
|
assert.Equal(t, events.SettingsFailed.String(), eventName)
|
|
|
|
eventConfig := trace.NewEventConfig(opts)
|
|
attrs := eventConfig.Attributes()
|
|
|
|
assert.Contains(t, attrs, attribute.String("IdentityID", identityID.String()))
|
|
assert.Contains(t, attrs, attribute.String("SelfServiceFlowType", "browser"))
|
|
assert.Contains(t, attrs, attribute.String("SelfServiceMethodUsed", "password"))
|
|
})
|
|
}
|
|
|
|
func TestNewVerificationFailed(t *testing.T) {
|
|
ctx := t.Context()
|
|
flowID := uuid.Must(uuid.NewV4())
|
|
identityID := uuid.Must(uuid.NewV4())
|
|
baseErr := errors.New("verification failed")
|
|
|
|
t.Run("case=without identity ID", func(t *testing.T) {
|
|
eventName, opts := events.NewVerificationFailed(ctx, flowID, "browser", "code", baseErr)
|
|
|
|
assert.Equal(t, events.VerificationFailed.String(), eventName)
|
|
|
|
eventConfig := trace.NewEventConfig(opts)
|
|
attrs := eventConfig.Attributes()
|
|
|
|
for _, attr := range attrs {
|
|
assert.NotEqual(t, "IdentityID", string(attr.Key))
|
|
}
|
|
|
|
assert.Contains(t, attrs, attribute.String("SelfServiceFlowType", "browser"))
|
|
assert.Contains(t, attrs, attribute.String("SelfServiceMethodUsed", "code"))
|
|
})
|
|
|
|
t.Run("case=with identity ID", func(t *testing.T) {
|
|
wrappedErr := x.WrapWithIdentityIDError(baseErr, identityID)
|
|
eventName, opts := events.NewVerificationFailed(ctx, flowID, "browser", "link", wrappedErr)
|
|
|
|
assert.Equal(t, events.VerificationFailed.String(), eventName)
|
|
|
|
eventConfig := trace.NewEventConfig(opts)
|
|
attrs := eventConfig.Attributes()
|
|
|
|
assert.Contains(t, attrs, attribute.String("IdentityID", identityID.String()))
|
|
assert.Contains(t, attrs, attribute.String("SelfServiceFlowType", "browser"))
|
|
assert.Contains(t, attrs, attribute.String("SelfServiceMethodUsed", "link"))
|
|
})
|
|
}
|
|
|
|
func TestNewCourierMessageDispatched(t *testing.T) {
|
|
t.Parallel()
|
|
nid := uuid.Must(uuid.NewV4())
|
|
msgID := uuid.Must(uuid.NewV4())
|
|
ctx := semconv.ContextWithAttributes(t.Context(), attribute.String("ProjectID", nid.String()))
|
|
|
|
eventName, opts := events.NewCourierMessageDispatched(ctx, msgID, "smtp", "stub")
|
|
|
|
assert.Equal(t, events.CourierMessageDispatched.String(), eventName)
|
|
|
|
eventConfig := trace.NewEventConfig(opts)
|
|
attrs := eventConfig.Attributes()
|
|
|
|
assert.Contains(t, attrs, attribute.String("ProjectID", nid.String()))
|
|
assert.Contains(t, attrs, attribute.String("CourierMessageID", msgID.String()))
|
|
assert.Contains(t, attrs, attribute.String("CourierMessageChannel", "smtp"))
|
|
assert.Contains(t, attrs, attribute.String("CourierMessageTemplateType", "stub"))
|
|
}
|
|
|
|
func TestNewCourierMessageAbandoned(t *testing.T) {
|
|
t.Parallel()
|
|
nid := uuid.Must(uuid.NewV4())
|
|
msgID := uuid.Must(uuid.NewV4())
|
|
ctx := semconv.ContextWithAttributes(t.Context(), attribute.String("ProjectID", nid.String()))
|
|
|
|
eventName, opts := events.NewCourierMessageAbandoned(ctx, msgID, "http", "recovery")
|
|
|
|
assert.Equal(t, events.CourierMessageAbandoned.String(), eventName)
|
|
|
|
eventConfig := trace.NewEventConfig(opts)
|
|
attrs := eventConfig.Attributes()
|
|
|
|
assert.Contains(t, attrs, attribute.String("ProjectID", nid.String()))
|
|
assert.Contains(t, attrs, attribute.String("CourierMessageID", msgID.String()))
|
|
assert.Contains(t, attrs, attribute.String("CourierMessageChannel", "http"))
|
|
assert.Contains(t, attrs, attribute.String("CourierMessageTemplateType", "recovery"))
|
|
}
|