feat: mail service
This commit is contained in:
@@ -0,0 +1,189 @@
|
||||
package mail
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestDeliveryCommandsAsyncAPISpecLoads(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
doc := loadAsyncAPISpec(t)
|
||||
require.Equal(t, "3.1.0", getStringValue(t, doc, "asyncapi"))
|
||||
}
|
||||
|
||||
func TestDeliveryCommandsAsyncAPISpecFreezesChannelAndOperation(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
doc := loadAsyncAPISpec(t)
|
||||
|
||||
channel := getMapValue(t, doc, "channels", "deliveryCommands")
|
||||
require.Equal(t, "mail:delivery_commands", getStringValue(t, channel, "address"))
|
||||
|
||||
channelMessages := getMapValue(t, channel, "messages")
|
||||
require.Equal(t, "#/components/messages/RenderedDeliveryCommand", getStringValue(t, getMapValue(t, channelMessages, "renderedDeliveryCommand"), "$ref"))
|
||||
require.Equal(t, "#/components/messages/TemplateDeliveryCommand", getStringValue(t, getMapValue(t, channelMessages, "templateDeliveryCommand"), "$ref"))
|
||||
|
||||
operation := getMapValue(t, doc, "operations", "publishDeliveryCommand")
|
||||
require.Equal(t, "send", getStringValue(t, operation, "action"))
|
||||
require.Equal(t, "#/channels/deliveryCommands", getStringValue(t, getMapValue(t, operation, "channel"), "$ref"))
|
||||
|
||||
messageRefs := getSliceValue(t, operation, "messages")
|
||||
require.Len(t, messageRefs, 2)
|
||||
require.Equal(t, "#/channels/deliveryCommands/messages/renderedDeliveryCommand", getStringValue(t, messageRefs[0].(map[string]any), "$ref"))
|
||||
require.Equal(t, "#/channels/deliveryCommands/messages/templateDeliveryCommand", getStringValue(t, messageRefs[1].(map[string]any), "$ref"))
|
||||
}
|
||||
|
||||
func TestDeliveryCommandsAsyncAPISpecFreezesEnvelopeSchemas(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
doc := loadAsyncAPISpec(t)
|
||||
schemas := getMapValue(t, getMapValue(t, doc, "components"), "schemas")
|
||||
|
||||
renderedEnvelope := getMapValue(t, schemas, "RenderedDeliveryCommandEnvelope")
|
||||
require.ElementsMatch(
|
||||
t,
|
||||
[]any{"delivery_id", "source", "payload_mode", "idempotency_key", "requested_at_ms", "payload_json"},
|
||||
getSliceValue(t, renderedEnvelope, "required"),
|
||||
)
|
||||
require.Equal(t, "notification", getScalarValue(t, getMapValue(t, getMapValue(t, renderedEnvelope, "properties"), "source"), "const"))
|
||||
require.Equal(t, "rendered", getScalarValue(t, getMapValue(t, getMapValue(t, renderedEnvelope, "properties"), "payload_mode"), "const"))
|
||||
require.Equal(
|
||||
t,
|
||||
"#/components/schemas/RenderedPayloadJSON",
|
||||
getStringValue(t, getMapValue(t, getMapValue(t, getMapValue(t, renderedEnvelope, "properties"), "payload_json"), "contentSchema"), "$ref"),
|
||||
)
|
||||
|
||||
templateEnvelope := getMapValue(t, schemas, "TemplateDeliveryCommandEnvelope")
|
||||
require.Equal(t, "notification", getScalarValue(t, getMapValue(t, getMapValue(t, templateEnvelope, "properties"), "source"), "const"))
|
||||
require.Equal(t, "template", getScalarValue(t, getMapValue(t, getMapValue(t, templateEnvelope, "properties"), "payload_mode"), "const"))
|
||||
require.Equal(
|
||||
t,
|
||||
"#/components/schemas/TemplatePayloadJSON",
|
||||
getStringValue(t, getMapValue(t, getMapValue(t, getMapValue(t, templateEnvelope, "properties"), "payload_json"), "contentSchema"), "$ref"),
|
||||
)
|
||||
}
|
||||
|
||||
func TestDeliveryCommandsAsyncAPISpecFreezesPayloadSchemasAndExamples(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
doc := loadAsyncAPISpec(t)
|
||||
components := getMapValue(t, doc, "components")
|
||||
schemas := getMapValue(t, components, "schemas")
|
||||
messages := getMapValue(t, components, "messages")
|
||||
|
||||
renderedPayload := getMapValue(t, schemas, "RenderedPayloadJSON")
|
||||
require.ElementsMatch(
|
||||
t,
|
||||
[]any{"to", "cc", "bcc", "reply_to", "subject", "text_body", "attachments"},
|
||||
getSliceValue(t, renderedPayload, "required"),
|
||||
)
|
||||
|
||||
templatePayload := getMapValue(t, schemas, "TemplatePayloadJSON")
|
||||
require.ElementsMatch(
|
||||
t,
|
||||
[]any{"to", "cc", "bcc", "reply_to", "template_id", "locale", "variables", "attachments"},
|
||||
getSliceValue(t, templatePayload, "required"),
|
||||
)
|
||||
|
||||
attachment := getMapValue(t, schemas, "Attachment")
|
||||
require.ElementsMatch(
|
||||
t,
|
||||
[]any{"filename", "content_type", "content_base64"},
|
||||
getSliceValue(t, attachment, "required"),
|
||||
)
|
||||
|
||||
renderedExamples := getSliceValue(t, getMapValue(t, messages, "RenderedDeliveryCommand"), "examples")
|
||||
require.NotEmpty(t, getStringValue(t, getMapValue(t, renderedExamples[0].(map[string]any), "payload"), "payload_json"))
|
||||
|
||||
templateExamples := getSliceValue(t, getMapValue(t, messages, "TemplateDeliveryCommand"), "examples")
|
||||
require.NotEmpty(t, getStringValue(t, getMapValue(t, templateExamples[0].(map[string]any), "payload"), "payload_json"))
|
||||
}
|
||||
|
||||
func loadAsyncAPISpec(t *testing.T) map[string]any {
|
||||
t.Helper()
|
||||
|
||||
_, thisFile, _, ok := runtime.Caller(0)
|
||||
if !ok {
|
||||
require.FailNow(t, "runtime.Caller failed")
|
||||
}
|
||||
|
||||
specPath := filepath.Join(filepath.Dir(thisFile), "api", "delivery-commands-asyncapi.yaml")
|
||||
payload, err := os.ReadFile(specPath)
|
||||
if err != nil {
|
||||
require.Failf(t, "test failed", "read spec %s: %v", specPath, err)
|
||||
}
|
||||
|
||||
var doc map[string]any
|
||||
if err := yaml.Unmarshal(payload, &doc); err != nil {
|
||||
require.Failf(t, "test failed", "decode spec %s: %v", specPath, err)
|
||||
}
|
||||
|
||||
return doc
|
||||
}
|
||||
|
||||
func getMapValue(t *testing.T, value map[string]any, path ...string) map[string]any {
|
||||
t.Helper()
|
||||
|
||||
current := value
|
||||
for _, segment := range path {
|
||||
raw, ok := current[segment]
|
||||
if !ok {
|
||||
require.Failf(t, "test failed", "missing map key %s", segment)
|
||||
}
|
||||
next, ok := raw.(map[string]any)
|
||||
if !ok {
|
||||
require.Failf(t, "test failed", "value at %s is not a map", segment)
|
||||
}
|
||||
current = next
|
||||
}
|
||||
|
||||
return current
|
||||
}
|
||||
|
||||
func getStringValue(t *testing.T, value map[string]any, key string) string {
|
||||
t.Helper()
|
||||
|
||||
raw, ok := value[key]
|
||||
if !ok {
|
||||
require.Failf(t, "test failed", "missing key %s", key)
|
||||
}
|
||||
result, ok := raw.(string)
|
||||
if !ok {
|
||||
require.Failf(t, "test failed", "value at %s is not a string", key)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func getScalarValue(t *testing.T, value map[string]any, key string) any {
|
||||
t.Helper()
|
||||
|
||||
raw, ok := value[key]
|
||||
if !ok {
|
||||
require.Failf(t, "test failed", "missing key %s", key)
|
||||
}
|
||||
|
||||
return raw
|
||||
}
|
||||
|
||||
func getSliceValue(t *testing.T, value map[string]any, key string) []any {
|
||||
t.Helper()
|
||||
|
||||
raw, ok := value[key]
|
||||
if !ok {
|
||||
require.Failf(t, "test failed", "missing key %s", key)
|
||||
}
|
||||
result, ok := raw.([]any)
|
||||
if !ok {
|
||||
require.Failf(t, "test failed", "value at %s is not a slice", key)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
Reference in New Issue
Block a user