feat: notification service

This commit is contained in:
Ilia Denisov
2026-04-22 08:49:45 +02:00
committed by GitHub
parent 5b7593e6f6
commit 32dc29359a
135 changed files with 21828 additions and 130 deletions
@@ -26,9 +26,9 @@ func TestServiceExecuteRendersExactLocale(t *testing.T) {
catalog := newTestCatalog(t, map[string]string{
filepath.Join("auth.login_code", "en", "subject.tmpl"): "Your login code",
filepath.Join("auth.login_code", "en", "text.tmpl"): "Code: {{.code}}",
filepath.Join("game.turn_ready", "fr-fr", "subject.tmpl"): "Tour {{.turn_number}}",
filepath.Join("game.turn_ready", "fr-fr", "text.tmpl"): "Bonjour {{with .player}}{{.name}}{{end}}",
filepath.Join("game.turn_ready", "fr-fr", "html.tmpl"): "<p>{{.player.name}}</p>",
filepath.Join("game.turn.ready", "fr-fr", "subject.tmpl"): "Tour {{.turn_number}}",
filepath.Join("game.turn.ready", "fr-fr", "text.tmpl"): "Bonjour {{with .player}}{{.name}}{{end}}",
filepath.Join("game.turn.ready", "fr-fr", "html.tmpl"): "<p>{{.player.name}}</p>",
})
store := &stubStore{}
@@ -61,8 +61,8 @@ func TestServiceExecuteFallsBackToEnglish(t *testing.T) {
catalog := newTestCatalog(t, map[string]string{
filepath.Join("auth.login_code", "en", "subject.tmpl"): "Your login code",
filepath.Join("auth.login_code", "en", "text.tmpl"): "Code: {{.code}}",
filepath.Join("game.turn_ready", "en", "subject.tmpl"): "Turn {{.turn_number}}",
filepath.Join("game.turn_ready", "en", "text.tmpl"): "Hello {{.player.name}}",
filepath.Join("game.turn.ready", "en", "subject.tmpl"): "Turn {{.turn_number}}",
filepath.Join("game.turn.ready", "en", "text.tmpl"): "Hello {{.player.name}}",
})
store := &stubStore{}
@@ -86,8 +86,8 @@ func TestServiceExecuteRecordsLocaleFallbackAndLogsFields(t *testing.T) {
catalog := newTestCatalog(t, map[string]string{
filepath.Join("auth.login_code", "en", "subject.tmpl"): "Your login code",
filepath.Join("auth.login_code", "en", "text.tmpl"): "Code: {{.code}}",
filepath.Join("game.turn_ready", "en", "subject.tmpl"): "Turn {{.turn_number}}",
filepath.Join("game.turn_ready", "en", "text.tmpl"): "Hello {{.player.name}}",
filepath.Join("game.turn.ready", "en", "subject.tmpl"): "Turn {{.turn_number}}",
filepath.Join("game.turn.ready", "en", "text.tmpl"): "Hello {{.player.name}}",
})
telemetry := &stubTelemetry{}
@@ -107,10 +107,10 @@ func TestServiceExecuteRecordsLocaleFallbackAndLogsFields(t *testing.T) {
_, err := service.Execute(context.Background(), validInput(t, "fr-FR"))
require.NoError(t, err)
require.Equal(t, []string{"notification:rendered"}, telemetry.statuses)
require.Equal(t, []string{"game.turn_ready:fr-FR:en"}, telemetry.fallbacks)
require.Equal(t, []string{"game.turn.ready:fr-FR:en"}, telemetry.fallbacks)
require.Contains(t, loggerBuffer.String(), "\"delivery_id\":\"delivery-123\"")
require.Contains(t, loggerBuffer.String(), "\"source\":\"notification\"")
require.Contains(t, loggerBuffer.String(), "\"template_id\":\"game.turn_ready\"")
require.Contains(t, loggerBuffer.String(), "\"template_id\":\"game.turn.ready\"")
require.Contains(t, loggerBuffer.String(), "\"attempt_no\":1")
require.Contains(t, loggerBuffer.String(), "\"otel_trace_id\":")
require.True(t, hasRenderSpanNamed(recorder.Ended(), "mail.render_delivery"))
@@ -122,8 +122,8 @@ func TestServiceExecuteFailsOnMissingRequiredVariable(t *testing.T) {
catalog := newTestCatalog(t, map[string]string{
filepath.Join("auth.login_code", "en", "subject.tmpl"): "Your login code",
filepath.Join("auth.login_code", "en", "text.tmpl"): "Code: {{.code}}",
filepath.Join("game.turn_ready", "en", "subject.tmpl"): "Turn {{.turn_number}}",
filepath.Join("game.turn_ready", "en", "text.tmpl"): "Hello {{.player.name}}",
filepath.Join("game.turn.ready", "en", "subject.tmpl"): "Turn {{.turn_number}}",
filepath.Join("game.turn.ready", "en", "text.tmpl"): "Hello {{.player.name}}",
})
store := &stubStore{}
@@ -153,8 +153,8 @@ func TestServiceExecuteFailsOnTemplateExecutionError(t *testing.T) {
catalog := newTestCatalog(t, map[string]string{
filepath.Join("auth.login_code", "en", "subject.tmpl"): "Your login code",
filepath.Join("auth.login_code", "en", "text.tmpl"): "Code: {{.code}}",
filepath.Join("game.turn_ready", "en", "subject.tmpl"): "{{call .callable}}",
filepath.Join("game.turn_ready", "en", "text.tmpl"): "Hello {{.player.name}}",
filepath.Join("game.turn.ready", "en", "subject.tmpl"): "{{call .callable}}",
filepath.Join("game.turn.ready", "en", "text.tmpl"): "Hello {{.player.name}}",
})
store := &stubStore{}
@@ -231,8 +231,8 @@ func TestServiceExecuteReturnsServiceUnavailableOnStoreFailure(t *testing.T) {
catalog := newTestCatalog(t, map[string]string{
filepath.Join("auth.login_code", "en", "subject.tmpl"): "Your login code",
filepath.Join("auth.login_code", "en", "text.tmpl"): "Code: {{.code}}",
filepath.Join("game.turn_ready", "en", "subject.tmpl"): "Turn {{.turn_number}}",
filepath.Join("game.turn_ready", "en", "text.tmpl"): "Hello {{.player.name}}",
filepath.Join("game.turn.ready", "en", "subject.tmpl"): "Turn {{.turn_number}}",
filepath.Join("game.turn.ready", "en", "text.tmpl"): "Hello {{.player.name}}",
})
service := newTestService(t, Config{
@@ -346,7 +346,7 @@ func validInput(t *testing.T, localeValue string) Input {
DeliveryID: common.DeliveryID("delivery-123"),
Source: deliverydomain.SourceNotification,
PayloadMode: deliverydomain.PayloadModeTemplate,
TemplateID: common.TemplateID("game.turn_ready"),
TemplateID: common.TemplateID("game.turn.ready"),
Envelope: deliverydomain.Envelope{
To: []common.Email{common.Email("pilot@example.com")},
},