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 }