#!/usr/bin/env elixir # Test Enhanced Supervisor Configuration # Run with: elixir test_supervisor_config.exs Mix.install([]) defmodule SupervisorConfigTest do @moduledoc """ Test the configuration loading and Ranch setup for EnhancedDeviceListenerSupervisor. """ require Logger def test_configuration do IO.puts("=== Enhanced Supervisor Configuration Test ===\n") # Test configuration loading test_config_loading() # Test Ranch configuration generation test_ranch_config_generation() # Test listener normalization test_listener_normalization() IO.puts("\n=== Configuration Test Complete ===") end defp test_config_loading do IO.puts("๐Ÿงช Testing Configuration Loading...") # Mock the device_listeners configuration mock_device_listeners = [ %{ id: :legacy_mercury_listener, port: 5000, protocol: DaProductApp.Switch.Protocol, max_connections: 100, name: "Legacy Mercury Device Listener", ranch_opts: [] }, %{ id: :enhanced_primary_listener, port: 8583, protocol: DaProductApp.Switch.EnhancedProtocol, max_connections: 100, name: "Enhanced Primary ISO8583 Listener", ranch_opts: [] } ] IO.puts(" ๐Ÿ“‹ Mock configuration loaded:") Enum.each(mock_device_listeners, fn listener -> IO.puts(" - #{listener.name} (Port #{listener.port})") IO.puts(" ID: #{listener.id}") IO.puts(" Protocol: #{listener.protocol}") IO.puts(" Max Connections: #{listener.max_connections}") IO.puts(" Ranch Opts: #{inspect(listener.ranch_opts)}") IO.puts("") end) mock_device_listeners end defp test_ranch_config_generation do IO.puts("๐Ÿงช Testing Ranch Configuration Generation...") # Test listener config listener_config = %{ id: :test_listener, port: 9999, protocol: TestProtocol, max_connections: 10, name: "Test Listener", ranch_opts: [:binary, {:reuseaddr, true}] } # Generate Ranch configuration (mimic the supervisor logic) ranch_opts = %{ socket_opts: [ port: listener_config.port ] ++ Map.get(listener_config, :ranch_opts, []), max_connections: listener_config.max_connections } IO.puts(" ๐Ÿ“‹ Generated Ranch configuration:") IO.puts(" Listener Config: #{inspect(listener_config, pretty: true)}") IO.puts(" Ranch Opts: #{inspect(ranch_opts, pretty: true)}") # Validate the structure socket_opts = Map.get(ranch_opts, :socket_opts, []) max_connections = Map.get(ranch_opts, :max_connections) if is_list(socket_opts) and is_integer(max_connections) do IO.puts(" โœ… Ranch configuration structure is valid") else IO.puts(" โŒ Ranch configuration structure is invalid") IO.puts(" socket_opts type: #{inspect(socket_opts |> is_list())}") IO.puts(" max_connections type: #{inspect(max_connections |> is_integer())}") end # Test if port is in socket_opts port = Keyword.get(socket_opts, :port) if port == listener_config.port do IO.puts(" โœ… Port correctly placed in socket_opts") else IO.puts(" โŒ Port not found in socket_opts") end IO.puts("") ranch_opts end defp test_listener_normalization do IO.puts("๐Ÿงช Testing Listener Normalization...") # Test different input formats test_cases = [ # Standard format %{ id: :test1, port: 8000, protocol: TestProtocol, max_connections: 50, name: "Test 1", ranch_opts: [] }, # Missing optional fields %{ id: :test2, port: 8001, protocol: TestProtocol, max_connections: 25 }, # With ranch_opts %{ id: :test3, port: 8002, protocol: TestProtocol, max_connections: 75, name: "Test 3", ranch_opts: [:binary, {:active, false}] } ] Enum.each(test_cases, fn config -> normalized = normalize_test_config(config) IO.puts(" ๐Ÿ“‹ Input: #{inspect(config, limit: 3)}") IO.puts(" Output: #{inspect(normalized, limit: 3)}") # Validate normalized config required_keys = [:id, :port, :protocol, :max_connections, :name, :ranch_opts] missing_keys = Enum.filter(required_keys, fn key -> not Map.has_key?(normalized, key) end) if Enum.empty?(missing_keys) do IO.puts(" โœ… Normalized config is complete") else IO.puts(" โŒ Missing keys: #{inspect(missing_keys)}") end IO.puts("") end) end # Helper function that mimics the supervisor's normalize_listener_config defp normalize_test_config(config) when is_map(config) do %{ id: Map.fetch!(config, :id), port: Map.fetch!(config, :port), protocol: Map.get(config, :protocol, DaProductApp.Switch.EnhancedProtocol), max_connections: Map.get(config, :max_connections, 50), name: Map.get(config, :name, "Device Listener #{config.port}"), ranch_opts: Map.get(config, :ranch_opts, []) } end def create_test_child_spec(listener_config) do IO.puts("๐Ÿงช Creating Child Spec for: #{listener_config.name}") # Ranch expects a map with socket_opts as a nested list ranch_opts = %{ socket_opts: [ port: listener_config.port ] ++ Map.get(listener_config, :ranch_opts, []), max_connections: listener_config.max_connections } child_spec = %{ id: listener_config.id, start: {:ranch, :start_listener, [ listener_config.id, :ranch_tcp, ranch_opts, listener_config.protocol, [] ]}, type: :supervisor, restart: :permanent, shutdown: 5000 } IO.puts(" ๐Ÿ“‹ Child Spec Created:") IO.puts(" ID: #{child_spec.id}") IO.puts(" Ranch Args: [") IO.puts(" listener_id: #{elem(elem(child_spec.start, 2), 0)}") IO.puts(" transport: #{elem(elem(child_spec.start, 2), 1)}") IO.puts(" opts: #{inspect(elem(elem(child_spec.start, 2), 2), pretty: true)}") IO.puts(" protocol: #{elem(elem(child_spec.start, 2), 3)}") IO.puts(" protocol_opts: #{inspect(elem(elem(child_spec.start, 2), 4))}") IO.puts(" ]") # Validate Ranch arguments [listener_id, transport, opts, protocol, protocol_opts] = elem(child_spec.start, 2) validations = [ {"Listener ID is atom", is_atom(listener_id)}, {"Transport is :ranch_tcp", transport == :ranch_tcp}, {"Opts is map", is_map(opts)}, {"socket_opts exists", Map.has_key?(opts, :socket_opts)}, {"socket_opts is list", is_list(Map.get(opts, :socket_opts))}, {"max_connections exists", Map.has_key?(opts, :max_connections)}, {"max_connections is integer", is_integer(Map.get(opts, :max_connections))}, {"Protocol is atom", is_atom(protocol)}, {"Protocol opts is list", is_list(protocol_opts)} ] IO.puts(" ๐Ÿ” Validation Results:") Enum.each(validations, fn {test, result} -> status = if result, do: "โœ…", else: "โŒ" IO.puts(" #{status} #{test}") end) IO.puts("") child_spec end end # Run the tests IO.puts("Starting Enhanced Supervisor Configuration Test...") SupervisorConfigTest.test_configuration() # Test child spec creation IO.puts("\n๐Ÿงช Testing Child Spec Creation...") test_config = %{ id: :test_listener, port: 9999, protocol: TestProtocol, max_connections: 10, name: "Test Listener", ranch_opts: [:binary] } SupervisorConfigTest.create_test_child_spec(test_config)