#!/usr/bin/env elixir # Test script for the enhanced architecture # Run with: elixir test_enhanced_architecture.exs Mix.install([]) defmodule EnhancedArchitectureTest do @moduledoc """ Test script for the enhanced message processing architecture. Tests: 1. Channel configuration management 2. Message processing flow 3. Upstream routing 4. Response handling """ require Logger # Mock modules for testing (since we can't load the full app) defmodule MockISOMsg do defstruct [:mti, :fields, :packager] def new(mti), do: {:ok, %__MODULE__{mti: mti, fields: %{}, packager: nil}} def get_mti(%__MODULE__{mti: mti}), do: mti def set(%__MODULE__{} = msg, field, value), do: %{msg | fields: Map.put(msg.fields, field, value)} def get_field(%__MODULE__{fields: fields}, field), do: Map.get(fields, field) def set_packager(%__MODULE__{} = msg, packager), do: %{msg | packager: packager} def pack(%__MODULE__{mti: mti, fields: fields}), do: {:ok, "PACKED:#{mti}:#{inspect(fields)}"} def unpack(data, _packager), do: {:ok, %__MODULE__{mti: "0200", fields: %{2 => "4111111111111111", 3 => "000000", 4 => "000001000000"}}} end def run_tests do IO.puts("=== Enhanced Architecture Test Suite ===\n") # Test 1: Channel Configuration test_channel_configuration() # Test 2: Message Processing Flow test_message_processing_flow() # Test 3: Upstream Routing Rules test_upstream_routing_rules() # Test 4: Error Handling test_error_handling() IO.puts("\n=== All Tests Completed ===") end defp test_channel_configuration do IO.puts("๐Ÿงช Testing Channel Configuration...") # Test channel config structure channel_config = %{ name: "test_channel", packager: DaProductApp.MercuryISO8583.Packagers.ISO87BPackager, protocol: DaProductApp.Switch.EnhancedProtocol, max_connections: 10, timeout: 15_000, transformations: [:normalize_amounts], validation_rules: :standard } # Validate required fields required_fields = [:name, :packager, :protocol] missing_fields = Enum.filter(required_fields, fn field -> not Map.has_key?(channel_config, field) end) if Enum.empty?(missing_fields) do IO.puts(" โœ… Channel configuration structure valid") else IO.puts(" โŒ Missing required fields: #{inspect(missing_fields)}") end # Test channel context creation channel_context = %{ port: 8583, name: channel_config.name, packager: channel_config.packager, protocol: channel_config.protocol, validation_rules: channel_config.validation_rules, transformations: channel_config.transformations, socket_info: %{}, created_at: DateTime.utc_now() } IO.puts(" โœ… Channel context created: #{channel_context.name}") IO.puts("") end defp test_message_processing_flow do IO.puts("๐Ÿงช Testing Message Processing Flow...") # Create test message {:ok, iso_message} = MockISOMsg.new("0200") iso_message = iso_message |> MockISOMsg.set(2, "4111111111111111") # PAN |> MockISOMsg.set(3, "000000") # Processing code |> MockISOMsg.set(4, "000001000000") # Amount |> MockISOMsg.set(11, "123456") # STAN |> MockISOMsg.set(37, "123456789012") # RRN |> MockISOMsg.set(41, "TERM0001") # Terminal ID |> MockISOMsg.set(42, "MERCHANT000001") # Merchant ID IO.puts(" โœ… Created test message MTI: #{MockISOMsg.get_mti(iso_message)}") # Test message enrichment enriched_message = iso_message |> MockISOMsg.set("_processing_timestamp", DateTime.utc_now() |> DateTime.to_string()) |> MockISOMsg.set("_channel_port", 8583) |> MockISOMsg.set("_trace_id", "TRACE123") IO.puts(" โœ… Message enriched with processing metadata") # Test packing/unpacking case MockISOMsg.pack(enriched_message) do {:ok, packed_data} -> IO.puts(" โœ… Message packed: #{String.slice(packed_data, 0, 50)}...") case MockISOMsg.unpack(packed_data, :mock_packager) do {:ok, unpacked_message} -> IO.puts(" โœ… Message unpacked successfully") {:error, reason} -> IO.puts(" โŒ Message unpacking failed: #{inspect(reason)}") end {:error, reason} -> IO.puts(" โŒ Message packing failed: #{inspect(reason)}") end IO.puts("") end defp test_upstream_routing_rules do IO.puts("๐Ÿงช Testing Upstream Routing Rules...") # Test BIN range matching {:ok, visa_message} = MockISOMsg.new("0200") visa_message = MockISOMsg.set(visa_message, 2, "4111111111111111") # Visa BIN visa_rules = [ {:bin_range, "400000-499999"}, {:mti_pattern, "01??"} ] # Test BIN range rule pan = MockISOMsg.get_field(visa_message, 2) bin = String.slice(pan, 0, 6) bin_matches = bin >= "400000" and bin <= "499999" if bin_matches do IO.puts(" โœ… BIN range rule matches for Visa card") else IO.puts(" โŒ BIN range rule failed for Visa card") end # Test MTI pattern matching mti = MockISOMsg.get_mti(visa_message) mti_matches = String.starts_with?(mti, "0") # Simplified pattern matching if mti_matches do IO.puts(" โœ… MTI pattern rule evaluation works") else IO.puts(" โŒ MTI pattern rule failed") end # Test routing configuration upstream_config = %{ visa: %{ host: "visa-processor.example.com", port: 8583, packager: DaProductApp.MercuryISO8583.Packagers.ISO87BPackager, routing_rules: visa_rules }, default: %{ host: "default-processor.example.com", port: 8583, packager: DaProductApp.MercuryISO8583.Packagers.ISO87BPackager, routing_rules: [{:default, true}] } } IO.puts(" โœ… Upstream configuration structure valid") IO.puts("") end defp test_error_handling do IO.puts("๐Ÿงช Testing Error Handling...") # Test error response creation {:ok, original_message} = MockISOMsg.new("0200") original_message = original_message |> MockISOMsg.set(11, "123456") |> MockISOMsg.set(37, "123456789012") # Convert to response MTI original_mti = MockISOMsg.get_mti(original_message) response_mti = case original_mti do "0" <> rest -> "1" <> rest "2" <> rest -> "3" <> rest other -> other end if response_mti == "1200" do IO.puts(" โœ… MTI conversion to response format works") else IO.puts(" โŒ MTI conversion failed: #{response_mti}") end # Test error code mapping error_codes = %{ validation_failed: "30", business_logic_failed: "12", upstream_routing_failed: "91", system_error: "96" } IO.puts(" โœ… Error code mapping defined") # Test essential field copying essential_fields = [11, 7, 41, 42] # STAN, DateTime, Terminal ID, Merchant ID available_fields = Enum.filter(essential_fields, fn field -> MockISOMsg.get_field(original_message, field) != nil end) IO.puts(" โœ… Essential fields available for error response: #{inspect(available_fields)}") IO.puts("") end end # Run the tests EnhancedArchitectureTest.run_tests()