#!/usr/bin/env elixir # Test script to verify the message sanitization fix # This tests our defensive approach to handle corrupted ISOMsg fields Mix.install([ {:jason, "~> 1.3"} ]) defmodule TestMessageSanitization do @moduledoc """ Test the message sanitization approach to fix corrupted ISOMsg fields """ require Logger # Mock ISOComponent and ISOMsg for testing defmodule TestISOComponent do defstruct [:field_number, :value, :validated] def new(field_number, value \\ nil) do %__MODULE__{field_number: field_number, value: value, validated: false} end def set_value(%__MODULE__{} = component, value) do %{component | value: value, validated: false} end def get_value(%__MODULE__{value: value}), do: value end defmodule TestISOMsg do defstruct [:mti, :fields] def set(%__MODULE__{fields: fields} = msg, field_number, value) do component = TestISOComponent.new(field_number, value) updated_fields = Map.put(fields, field_number, component) %{msg | fields: updated_fields} end def get(%__MODULE__{fields: fields}, field_number) do case Map.get(fields, field_number) do nil -> nil component -> TestISOComponent.get_value(component) end end end # The sanitization function (based on our actual implementation) defp sanitize_iso_message(%TestISOMsg{} = message) do Logger.debug("Sanitizing ISO message to fix any corrupted fields") # Check if sanitization is needed corrupted_fields = message.fields |> Enum.filter(fn {_field_num, field_value} -> not is_struct(field_value) or not match?(%{value: _}, field_value) end) if Enum.empty?(corrupted_fields) do Logger.debug("No corrupted fields found, skipping sanitization") message else Logger.debug("Found #{length(corrupted_fields)} corrupted fields: #{inspect(Enum.map(corrupted_fields, fn {field_num, _} -> field_num end))}") # Create a new clean message with the same MTI clean_message = %TestISOMsg{mti: message.mti, fields: %{}} # Rebuild all fields properly using ISOMsg.set/3 sanitized_message = message.fields |> Enum.reduce(clean_message, fn {field_num, field_value}, acc_msg -> # Extract the actual value regardless of whether it's plain string or ISOComponent actual_value = case field_value do %{value: val} -> val # ISOComponent struct val when is_binary(val) -> val # Plain string val -> to_string(val) # Convert other types to string end # Use ISOMsg.set/3 to properly create ISOComponent structs TestISOMsg.set(acc_msg, field_num, actual_value) end) Logger.debug("Message sanitization completed - all fields now properly structured") sanitized_message end end def test_message_sanitization do Logger.info("=== Testing Message Sanitization ===") # Test 1: Clean message (no sanitization needed) Logger.info("\n--- Test 1: Clean message ---") clean_msg = %TestISOMsg{mti: "0200", fields: %{}} clean_msg = TestISOMsg.set(clean_msg, 24, "782") clean_msg = TestISOMsg.set(clean_msg, 41, "12345671") Logger.info("Clean message field 24: #{TestISOMsg.get(clean_msg, 24)}") sanitized_clean = sanitize_iso_message(clean_msg) Logger.info("After sanitization field 24: #{TestISOMsg.get(sanitized_clean, 24)}") # Test 2: Corrupted message (plain strings in fields) Logger.info("\n--- Test 2: Corrupted message ---") corrupted_msg = %TestISOMsg{ mti: "0200", fields: %{ 24 => "782", # Plain string (corrupted) 41 => "12345671", # Plain string (corrupted) 3 => TestISOComponent.new(3, "000000") # Proper ISOComponent } } Logger.info("Corrupted message fields: #{inspect(Map.keys(corrupted_msg.fields))}") # Try to access field values before sanitization Logger.info("Before sanitization - trying to get field 24...") try do field_24_value = case Map.get(corrupted_msg.fields, 24) do %{value: val} -> val val -> val end Logger.info("✅ Field 24 raw access works: #{field_24_value}") rescue exception -> Logger.error("❌ Field 24 raw access failed: #{inspect(exception)}") end # Now sanitize and test Logger.info("Sanitizing corrupted message...") sanitized_msg = sanitize_iso_message(corrupted_msg) Logger.info("After sanitization field 24: #{TestISOMsg.get(sanitized_msg, 24)}") Logger.info("After sanitization field 41: #{TestISOMsg.get(sanitized_msg, 41)}") Logger.info("After sanitization field 3: #{TestISOMsg.get(sanitized_msg, 3)}") # Test 3: Try to set fields on sanitized message (should work now) Logger.info("\n--- Test 3: Setting fields on sanitized message ---") try do updated_msg = TestISOMsg.set(sanitized_msg, 24, "999") # Should work now Logger.info("✅ Successfully set field 24 to new value: #{TestISOMsg.get(updated_msg, 24)}") rescue exception -> Logger.error("❌ Failed to set field on sanitized message: #{inspect(exception)}") end Logger.info("\n=== Message Sanitization Test Completed ===") end end # Run the test TestMessageSanitization.test_message_sanitization()