178 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Elixir
		
	
	
	
	
	
			
		
		
	
	
			178 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Elixir
		
	
	
	
	
	
defmodule Phoenix.PubSubTest do
 | 
						|
  @moduledoc """
 | 
						|
  Sets up PubSub Adapter testcases.
 | 
						|
 | 
						|
  ## Usage
 | 
						|
 | 
						|
  To test a PubSub adapter, set the `:test_adapter` on the `:phoenix_pubsub`
 | 
						|
  configuration and require this file, ie:
 | 
						|
 | 
						|
      # your_pubsub_adapter_test.exs
 | 
						|
      Application.put_env(:phoenix_pubsub, :test_adapter, {Phoenix.PubSub.PG2, []})
 | 
						|
      Code.require_file "../deps/phoenix_pubsub/test/shared/pubsub_test.exs", __DIR__
 | 
						|
 | 
						|
  """
 | 
						|
 | 
						|
  use ExUnit.Case, async: true
 | 
						|
  alias Phoenix.PubSub
 | 
						|
 | 
						|
  defp subscribers(config, topic) do
 | 
						|
    Registry.lookup(config.pubsub, topic)
 | 
						|
  end
 | 
						|
 | 
						|
  defp rpc(pid, func) do
 | 
						|
    Agent.get(pid, fn :ok -> func.() end)
 | 
						|
  end
 | 
						|
 | 
						|
  defp spawn_pid do
 | 
						|
    {:ok, pid} = Agent.start_link(fn -> :ok end)
 | 
						|
    pid
 | 
						|
  end
 | 
						|
 | 
						|
  defmodule CustomDispatcher do
 | 
						|
    def dispatch(entries, from, message) do
 | 
						|
      for {pid, metadata} <- entries do
 | 
						|
        send(pid, {:custom, metadata, from, message})
 | 
						|
      end
 | 
						|
 | 
						|
      :ok
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  setup config do
 | 
						|
    size = config[:pool_size] || 1
 | 
						|
    {adapter, adapter_opts} = Application.get_env(:phoenix_pubsub, :test_adapter)
 | 
						|
    adapter_opts = [adapter: adapter, name: config.test, pool_size: size] ++ adapter_opts
 | 
						|
    start_supervised!({Phoenix.PubSub, adapter_opts})
 | 
						|
 | 
						|
    opts = %{
 | 
						|
      pubsub: config.test,
 | 
						|
      topic: to_string(config.test),
 | 
						|
      pool_size: size,
 | 
						|
      node: Phoenix.PubSub.node_name(config.test)
 | 
						|
    }
 | 
						|
 | 
						|
    {:ok, opts}
 | 
						|
  end
 | 
						|
 | 
						|
  test "node_name/1 returns the node name", config do
 | 
						|
    assert is_atom(config.node) or is_binary(config.node)
 | 
						|
  end
 | 
						|
 | 
						|
  for size <- [1, 8] do
 | 
						|
    @tag pool_size: size
 | 
						|
    test "pool #{size}: subscribe and unsubscribe", config do
 | 
						|
      pid = spawn_pid()
 | 
						|
      assert subscribers(config, config.topic) |> length == 0
 | 
						|
      assert rpc(pid, fn -> PubSub.subscribe(config.pubsub, config.topic) end)
 | 
						|
      assert subscribers(config, config.topic) == [{pid, nil}]
 | 
						|
      assert rpc(pid, fn -> PubSub.unsubscribe(config.pubsub, config.topic) end)
 | 
						|
      assert subscribers(config, config.topic) |> length == 0
 | 
						|
    end
 | 
						|
 | 
						|
    @tag pool_size: size
 | 
						|
    test "pool #{size}: broadcast/3 and broadcast!/3 publishes message to each subscriber",
 | 
						|
         config do
 | 
						|
      PubSub.subscribe(config.pubsub, config.topic)
 | 
						|
      :ok = PubSub.broadcast(config.pubsub, config.topic, :ping)
 | 
						|
      assert_receive :ping
 | 
						|
      :ok = PubSub.broadcast!(config.pubsub, config.topic, :ping)
 | 
						|
      assert_receive :ping
 | 
						|
    end
 | 
						|
 | 
						|
    @tag pool_size: size
 | 
						|
    test "pool #{size}: broadcast/3 does not publish message to other topic subscribers",
 | 
						|
         config do
 | 
						|
      PubSub.subscribe(config.pubsub, "unknown")
 | 
						|
 | 
						|
      Enum.each(0..10, fn _ ->
 | 
						|
        rpc(spawn_pid(), fn -> PubSub.subscribe(config.pubsub, config.topic) end)
 | 
						|
      end)
 | 
						|
 | 
						|
      :ok = PubSub.broadcast(config.pubsub, config.topic, :ping)
 | 
						|
      refute_received :ping
 | 
						|
    end
 | 
						|
 | 
						|
    @tag pool_size: size
 | 
						|
    test "pool #{size}: broadcast_from/4 and broadcast_from!/4 skips sender", config do
 | 
						|
      PubSub.subscribe(config.pubsub, config.topic)
 | 
						|
 | 
						|
      PubSub.broadcast_from(config.pubsub, self(), config.topic, :ping)
 | 
						|
      refute_received :ping
 | 
						|
 | 
						|
      PubSub.broadcast_from!(config.pubsub, self(), config.topic, :ping)
 | 
						|
      refute_received :ping
 | 
						|
    end
 | 
						|
 | 
						|
    @tag pool_size: size
 | 
						|
    test "pool #{size}: unsubscribe on not subscribed topic noops", config do
 | 
						|
      assert :ok = PubSub.unsubscribe(config.pubsub, config.topic)
 | 
						|
      assert subscribers(config, config.topic) == []
 | 
						|
    end
 | 
						|
 | 
						|
    @tag pool_size: size
 | 
						|
    test "pool #{size}: direct_broadcast sends to given node", config do
 | 
						|
      PubSub.subscribe(config.pubsub, config.topic)
 | 
						|
 | 
						|
      PubSub.direct_broadcast(config.node, config.pubsub, config.topic, :ping)
 | 
						|
      assert_receive :ping
 | 
						|
 | 
						|
      PubSub.direct_broadcast!(config.node, config.pubsub, config.topic, :ping)
 | 
						|
      assert_receive :ping
 | 
						|
    end
 | 
						|
 | 
						|
    @tag pool_size: size
 | 
						|
    test "pool #{size}: direct_broadcast sends to unknown node", config do
 | 
						|
      PubSub.subscribe(config.pubsub, config.topic)
 | 
						|
 | 
						|
      PubSub.direct_broadcast(:"IDONTKNOW@127.0.0.1", config.pubsub, config.topic, :ping)
 | 
						|
      refute_received :ping
 | 
						|
 | 
						|
      PubSub.direct_broadcast!(:"IDONTKNOW@127.0.0.1", config.pubsub, config.topic, :ping)
 | 
						|
      refute_received :ping
 | 
						|
    end
 | 
						|
 | 
						|
    @tag pool_size: size
 | 
						|
    test "pool #{size}: local_broadcast sends to the current node", config do
 | 
						|
      PubSub.subscribe(config.pubsub, config.topic)
 | 
						|
 | 
						|
      PubSub.local_broadcast(config.pubsub, config.topic, :ping)
 | 
						|
      assert_receive :ping
 | 
						|
    end
 | 
						|
 | 
						|
    @tag pool_size: size
 | 
						|
    test "pool #{size}: local_broadcast_from/5 skips sender", config do
 | 
						|
      PubSub.subscribe(config.pubsub, config.topic)
 | 
						|
 | 
						|
      PubSub.local_broadcast_from(config.pubsub, self(), config.topic, :ping)
 | 
						|
      refute_received :ping
 | 
						|
    end
 | 
						|
 | 
						|
    @tag pool_size: size
 | 
						|
    test "pool #{size}: with custom dispatching", %{topic: topic, test: test, node: node} do
 | 
						|
      PubSub.subscribe(test, topic)
 | 
						|
      PubSub.subscribe(test, topic, metadata: :special)
 | 
						|
 | 
						|
      PubSub.broadcast(test, topic, :broadcast, CustomDispatcher)
 | 
						|
      assert_receive {:custom, nil, :none, :broadcast}
 | 
						|
      assert_receive {:custom, :special, :none, :broadcast}
 | 
						|
 | 
						|
      PubSub.broadcast_from(test, self(), topic, :broadcast_from, CustomDispatcher)
 | 
						|
      assert_receive {:custom, nil, pid, :broadcast_from} when pid == self()
 | 
						|
      assert_receive {:custom, :special, pid, :broadcast_from} when pid == self()
 | 
						|
 | 
						|
      PubSub.local_broadcast(test, topic, :local, CustomDispatcher)
 | 
						|
      assert_receive {:custom, nil, :none, :local}
 | 
						|
      assert_receive {:custom, :special, :none, :local}
 | 
						|
 | 
						|
      PubSub.local_broadcast_from(test, self(), topic, :local_from, CustomDispatcher)
 | 
						|
      assert_receive {:custom, nil, pid, :local_from} when pid == self()
 | 
						|
      assert_receive {:custom, :special, pid, :local_from} when pid == self()
 | 
						|
 | 
						|
      PubSub.direct_broadcast(node, test, topic, :direct, CustomDispatcher)
 | 
						|
      assert_receive {:custom, nil, :none, :direct}
 | 
						|
      assert_receive {:custom, :special, :none, :direct}
 | 
						|
    end
 | 
						|
  end
 | 
						|
end
 |