diff --git a/README.md b/README.md index 0c872ae..0ff1501 100644 --- a/README.md +++ b/README.md @@ -108,6 +108,67 @@ An example of handle_info end ``` +## Incremental Delivery + +AbsintheGraphqlWS supports GraphQL `@defer` and `@stream` directives for incremental delivery over WebSocket connections using the GraphQL-WS protocol. This enables real-time streaming of deferred fragments and list items while maintaining protocol compliance. + +Key features: +- ✅ **GraphQL-WS Protocol**: Full compliance with GraphQL-WS specification +- ✅ **Bidirectional Streaming**: Supports both client subscriptions and server-initiated streaming +- ✅ **Message Sequencing**: Proper ordering of initial, incremental, and completion messages +- ✅ **Error Handling**: Graceful error recovery and connection management + +**Installation with incremental delivery:** + +```elixir +def deps do + [ + {:absinthe, git: "https://github.com/gigsmart/absinthe.git", branch: "gigmart/defer-stream-incremental"}, + {:absinthe_graphql_ws, git: "https://github.com/gigsmart/absinthe_graphql_ws.git", branch: "gigmart/defer-stream-incremental"} + ] +end +``` + +**Example usage:** + +```javascript +// Client-side WebSocket connection +import { createClient } from 'graphql-ws'; + +const client = createClient({ + url: 'ws://localhost:4000/graphql/websocket' +}); + +const unsubscribe = client.subscribe( + { + query: ` + query GetUserProfile($userId: ID!) { + user(id: $userId) { + id + name + ... @defer(label: "profile") { + email + profile { bio } + } + posts @stream(initialCount: 2, label: "posts") { + id + title + } + } + } + `, + variables: { userId: "123" } + }, + { + next: (data) => console.log('Received data:', data), + error: (error) => console.error('GraphQL error:', error), + complete: () => console.log('Query completed') + } +); +``` + +For comprehensive documentation on WebSocket incremental delivery patterns, see [Absinthe Incremental Delivery Guide](https://hexdocs.pm/absinthe/incremental-delivery.html). + ## Benchmarks Benchmarks live in the `benchmarks` directory, and can be run with `MIX_ENV=bench mix run diff --git a/lib/absinthe/graphql_ws/client.ex b/lib/absinthe/graphql_ws/client.ex index 14efb5e..443bdd1 100644 --- a/lib/absinthe/graphql_ws/client.ex +++ b/lib/absinthe/graphql_ws/client.ex @@ -198,5 +198,5 @@ defmodule Absinthe.GraphqlWS.Client do end # defp debug(msg), do: Logger.debug("[client@#{inspect(self())}] #{msg}") - defp warn(msg), do: Logger.warn("[client@#{inspect(self())}] #{msg}") + defp warn(msg), do: Logger.warning("[client@#{inspect(self())}] #{msg}") end diff --git a/lib/absinthe/graphql_ws/incremental/transport.ex b/lib/absinthe/graphql_ws/incremental/transport.ex new file mode 100644 index 0000000..8ad6763 --- /dev/null +++ b/lib/absinthe/graphql_ws/incremental/transport.ex @@ -0,0 +1,203 @@ +defmodule Absinthe.GraphqlWS.Incremental.Transport do + @moduledoc """ + Incremental delivery support for the graphql-ws protocol. + + Implements @defer and @stream directives over the graphql-ws WebSocket protocol, + sending incremental payloads through Next messages while maintaining protocol compliance. + """ + + use Absinthe.Incremental.Transport + + alias Absinthe.GraphqlWS.Message + + require Logger + + @impl true + def init(socket, options) do + # Track active streaming operations + socket = socket + |> Map.put(:streaming_operations, %{}) + |> Map.put(:incremental_options, options) + + {:ok, socket} + end + + @impl true + def send_initial(%{current_operation_id: operation_id} = socket, response) do + # Send initial Next message with data and pending information + message = build_initial_message(operation_id, response) + + # Track this as an active streaming operation + socket = put_in( + socket.streaming_operations[operation_id], + %{ + pending: Map.get(response, :pending, []), + has_next: Map.get(response, :hasNext, false), + completed_count: 0, + total_count: length(Map.get(response, :pending, [])) + } + ) + + push_message(socket, message) + {:ok, socket} + end + + @impl true + def send_incremental(%{current_operation_id: operation_id} = socket, response) do + # Send incremental Next message + message = build_incremental_message(operation_id, response) + + # Update streaming operation state + socket = update_streaming_state(socket, operation_id, response) + + push_message(socket, message) + + # Check if we should send complete + if should_complete?(socket, operation_id) do + complete(socket) + else + {:ok, socket} + end + end + + @impl true + def complete(%{current_operation_id: operation_id} = socket) do + # Send Complete message to indicate end of stream + message = Message.Complete.new(operation_id) + + # Clean up streaming operation tracking + socket = update_in( + socket.streaming_operations, + &Map.delete(&1, operation_id) + ) + + push_message(socket, message) + :ok + end + + @impl true + def handle_error(socket, error) do + operation_id = socket.current_operation_id + + # Send error through Next message as per graphql-ws spec + error_response = format_error_response(error) + message = Message.Error.new(operation_id, error_response) + + push_message(socket, message) + + # Clean up if this was a fatal error + if fatal_error?(error) do + complete(socket) + else + {:ok, socket} + end + end + + @doc """ + Handle subscription with incremental delivery. + + Subscriptions can also use @defer and @stream within their selection sets. + """ + def handle_subscription_incremental(socket, subscription_id, incremental_response) do + # For subscriptions, we send incremental updates as part of the subscription stream + message = build_subscription_incremental_message(subscription_id, incremental_response) + push_message(socket, message) + {:ok, socket} + end + + @doc """ + Process an operation that contains @defer or @stream directives. + """ + def process_streaming_operation(socket, operation_id, blueprint) do + socket = Map.put(socket, :current_operation_id, operation_id) + + # Use the base transport's streaming handler + handle_streaming_response(socket, blueprint, []) + end + + # Private functions + + defp build_initial_message(operation_id, response) do + # Format the initial payload according to graphql-ws spec + # The response already contains data, pending, and hasNext + payload = response + + Message.Next.new(operation_id, payload) + end + + defp build_incremental_message(operation_id, response) do + # Format incremental payload + # Keep the incremental structure for clarity + payload = response + + Message.Next.new(operation_id, payload) + end + + defp build_subscription_incremental_message(subscription_id, response) do + # Wrap incremental response in subscription payload + payload = %{ + subscription: response + } + + Message.Next.new(subscription_id, payload) + end + + defp push_message(socket, message) do + # Send the message through the WebSocket + case socket do + %{transport_pid: pid} when is_pid(pid) -> + send(pid, {:push, {:text, message}}) + + _ -> + # Direct push for Phoenix.Socket + {:push, {:text, message}, socket} + end + end + + defp update_streaming_state(socket, operation_id, response) do + has_next = Map.get(response, :hasNext, false) + completed = Map.get(response, :completed, []) + + update_in( + socket.streaming_operations[operation_id], + fn state -> + state + |> Map.put(:has_next, has_next) + |> Map.update(:completed_count, length(completed), &(&1 + length(completed))) + end + ) + end + + defp should_complete?(socket, operation_id) do + case socket.streaming_operations[operation_id] do + %{has_next: false} -> true + %{completed_count: completed, total_count: total} when completed >= total -> true + _ -> false + end + end + + defp format_error_response(error) when is_binary(error) do + [%{message: error}] + end + + defp format_error_response(error) when is_map(error) do + [error] + end + + defp format_error_response(errors) when is_list(errors) do + errors + end + + defp format_error_response(error) do + [%{message: inspect(error)}] + end + + defp fatal_error?(error) do + # Determine if an error should terminate the stream + case error do + {:timeout, _} -> true + {:error, :max_complexity_exceeded} -> true + _ -> false + end + end +end \ No newline at end of file diff --git a/lib/absinthe/graphql_ws/transport.ex b/lib/absinthe/graphql_ws/transport.ex index 3abd93d..63cf227 100644 --- a/lib/absinthe/graphql_ws/transport.ex +++ b/lib/absinthe/graphql_ws/transport.ex @@ -24,7 +24,7 @@ defmodule Absinthe.GraphqlWS.Transport do @type socket() :: Socket.t() defmacrop debug(msg), do: quote(do: Logger.debug("[graph-socket@#{inspect(self())}] #{unquote(msg)}")) - defmacrop warn(msg), do: quote(do: Logger.warn("[graph-socket@#{inspect(self())}] #{unquote(msg)}")) + defmacrop warn(msg), do: quote(do: Logger.warning("[graph-socket@#{inspect(self())}] #{unquote(msg)}")) @doc """ Generally this will only receive `:pong` messages in response to our keepalive diff --git a/lib/absinthe/graphql_ws/transport_extensions.ex b/lib/absinthe/graphql_ws/transport_extensions.ex new file mode 100644 index 0000000..a0ec445 --- /dev/null +++ b/lib/absinthe/graphql_ws/transport_extensions.ex @@ -0,0 +1,190 @@ +defmodule Absinthe.GraphqlWS.TransportExtensions do + @moduledoc """ + Extensions to the base GraphQL-WS transport for @defer and @stream support. + + This module enhances the existing transport with incremental delivery capabilities, + detecting and handling operations that use @defer or @stream directives. + """ + + alias Absinthe.GraphqlWS.{Transport, Message} + alias Absinthe.GraphqlWS.Incremental + alias Absinthe.Phase.Document.Execution.StreamingResolution + + require Logger + + @doc """ + Enhanced subscribe handler that detects and handles @defer/@stream directives. + + This function wraps the standard subscribe handler to add incremental delivery support. + """ + def handle_subscribe_with_streaming(payload, id, socket) do + with {:ok, query} <- parse_query(payload), + {:ok, has_streaming} <- detect_streaming_directives(query) do + + if has_streaming do + handle_streaming_operation(payload, id, socket) + else + # Fallback to standard subscribe handling + Transport.handle_subscribe(payload, id, socket) + end + else + {:error, reason} -> + Logger.error("Failed to parse query for streaming detection: #{inspect(reason)}") + Transport.handle_subscribe(payload, id, socket) + end + end + + @doc """ + Process messages that may contain streaming operations. + + This can be used to wrap the existing handle_inbound function. + """ + def handle_inbound_with_streaming(%{"id" => id, "type" => "subscribe", "payload" => payload}, socket) do + handle_subscribe_with_streaming(payload, id, socket) + end + + def handle_inbound_with_streaming(msg, socket) do + # Delegate non-subscribe messages to standard handler + Transport.handle_inbound(msg, socket) + end + + @doc """ + Handle incremental responses received from streaming tasks. + """ + def handle_incremental_response({:incremental_response, operation_id, response}, socket) do + transport = Incremental.Transport + + socket = Map.put(socket, :current_operation_id, operation_id) + transport.send_incremental(socket, response) + end + + # Private functions + + defp parse_query(%{"query" => query}) when is_binary(query) do + {:ok, query} + end + defp parse_query(_), do: {:error, :no_query} + + defp detect_streaming_directives(query) do + # Simple detection - could be enhanced with proper AST parsing + has_defer = String.contains?(query, "@defer") + has_stream = String.contains?(query, "@stream") + {:ok, has_defer or has_stream} + end + + defp handle_streaming_operation(payload, id, socket) do + # Extract query and variables + query = Map.get(payload, "query", "") + variables = Map.get(payload, "variables", %{}) + + # Configure pipeline with streaming resolution + opts = build_streaming_options(socket, id, variables) + + # Execute with streaming-aware pipeline + case run_streaming_document(query, socket.absinthe.schema, opts) do + {:ok, blueprint} -> + # Set current operation ID for the transport + socket = Map.put(socket, :current_operation_id, id) + + # Process through incremental transport + transport = Incremental.Transport + transport.process_streaming_operation(socket, id, blueprint) + + {:error, errors} -> + {:push, {:text, Message.Error.new(id, errors)}, socket} + end + end + + defp build_streaming_options(socket, operation_id, variables) do + base_opts = socket.absinthe.opts || [] + + Keyword.merge(base_opts, [ + variables: variables, + operation_id: operation_id, + transport: Incremental.Transport, + context: %{ + pubsub: socket.pubsub, + operation_id: operation_id + } + ]) + end + + defp run_streaming_document(document, schema, opts) do + pipeline = build_streaming_pipeline(schema, opts) + + case Absinthe.Pipeline.run(document, pipeline) do + {:ok, %{result: result} = blueprint, _phases} -> + # Check if streaming was actually used + if streaming_enabled?(blueprint) do + {:ok, blueprint} + else + # Return as normal result + {:ok, result} + end + + {:error, msg, _phases} -> + {:error, msg} + end + end + + defp build_streaming_pipeline(schema, opts) do + # Build a pipeline that includes the streaming resolution phase + schema + |> Absinthe.Pipeline.for_document(opts) + |> replace_resolution_phase() + end + + defp replace_resolution_phase(pipeline) do + # Replace the standard resolution phase with streaming resolution + Enum.map(pipeline, fn + {Absinthe.Phase.Document.Execution.Resolution, opts} -> + {StreamingResolution, opts} + + phase -> + phase + end) + end + + defp streaming_enabled?(blueprint) do + get_in(blueprint, [:execution, :incremental_delivery]) == true + end + + @doc """ + Setup async handling for incremental responses. + + This spawns a task to handle the incremental delivery asynchronously. + """ + def setup_incremental_handler(socket, operation_id, blueprint) do + streaming_context = get_streaming_context(blueprint) + + if streaming_context do + Task.async(fn -> + process_incremental_tasks(socket, operation_id, streaming_context) + end) + end + + {:ok, socket} + end + + defp process_incremental_tasks(socket, operation_id, streaming_context) do + # Process deferred fragments + Enum.each(streaming_context.deferred_tasks || [], fn task -> + Process.sleep(1) # Small delay to prevent overwhelming the client + + result = task.execute.() + send(socket.transport_pid, {:incremental_response, operation_id, result}) + end) + + # Process streamed fields + Enum.each(streaming_context.stream_tasks || [], fn task -> + Process.sleep(1) + + result = task.execute.() + send(socket.transport_pid, {:incremental_response, operation_id, result}) + end) + end + + defp get_streaming_context(blueprint) do + get_in(blueprint, [:execution, :context, :__streaming__]) + end +end \ No newline at end of file diff --git a/mix.exs b/mix.exs index 3e1b58e..99e2780 100644 --- a/mix.exs +++ b/mix.exs @@ -29,8 +29,8 @@ defmodule AbsintheGraphqlWS.MixProject do defp deps do [ - {:absinthe, "~> 1.6"}, - {:absinthe_phoenix, "> 0.0.0"}, + {:absinthe, git: "https://github.com/gigsmart/absinthe.git", branch: "gigmart/defer-stream-incremental", override: true}, + {:absinthe_phoenix, "~> 2.0"}, {:benchee, "> 0.0.0", only: [:bench]}, {:credo, "~> 1.4", only: [:dev, :test], runtime: false}, {:cowlib, "~> 2.8", only: :test, override: true}, diff --git a/mix.lock b/mix.lock index 78b8617..45ba844 100644 --- a/mix.lock +++ b/mix.lock @@ -1,40 +1,42 @@ %{ - "absinthe": {:hex, :absinthe, "1.7.0", "36819e7b1fd5046c9c734f27fe7e564aed3bda59f0354c37cd2df88fd32dd014", [:mix], [{:dataloader, "~> 1.0.0", [hex: :dataloader, repo: "hexpm", optional: true]}, {:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0 or ~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "566a5b5519afc9b29c4d367f0c6768162de3ec03e9bf9916f9dc2bcbe7c09643"}, - "absinthe_phoenix": {:hex, :absinthe_phoenix, "2.0.2", "e607b438db900049b9b3760f8ecd0591017a46122fffed7057bf6989020992b5", [:mix], [{:absinthe, "~> 1.5", [hex: :absinthe, repo: "hexpm", optional: false]}, {:absinthe_plug, "~> 1.5", [hex: :absinthe_plug, repo: "hexpm", optional: false]}, {:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.5", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.13 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}], "hexpm", "d36918925c380dc7d2ed7d039c9a3b4182ec36723f7417a68745ade5aab22f8d"}, - "absinthe_plug": {:hex, :absinthe_plug, "1.5.8", "38d230641ba9dca8f72f1fed2dfc8abd53b3907d1996363da32434ab6ee5d6ab", [:mix], [{:absinthe, "~> 1.5", [hex: :absinthe, repo: "hexpm", optional: false]}, {:plug, "~> 1.4", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "bbb04176647b735828861e7b2705465e53e2cf54ccf5a73ddd1ebd855f996e5a"}, - "benchee": {:hex, :benchee, "1.1.0", "f3a43817209a92a1fade36ef36b86e1052627fd8934a8b937ac9ab3a76c43062", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}, {:statistex, "~> 1.0", [hex: :statistex, repo: "hexpm", optional: false]}], "hexpm", "7da57d545003165a012b587077f6ba90b89210fd88074ce3c60ce239eb5e6d93"}, - "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"}, - "cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"}, + "absinthe": {:git, "https://github.com/gigsmart/absinthe.git", "59606f2266f2cb3b818d5eba8501fd6087421814", [branch: "gigmart/defer-stream-incremental"]}, + "absinthe_phoenix": {:hex, :absinthe_phoenix, "2.0.3", "74e0862f280424b7bc290f6f69e133268bce0b4e7db0218c7e129c5c2b1d3fd4", [:mix], [{:absinthe, "~> 1.5", [hex: :absinthe, repo: "hexpm", optional: false]}, {:absinthe_plug, "~> 1.5", [hex: :absinthe_plug, repo: "hexpm", optional: false]}, {:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.5", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.13 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}], "hexpm", "caffaea03c17ea7419fe07e4bc04c2399c47f0d8736900623dbf4749a826fd2c"}, + "absinthe_plug": {:hex, :absinthe_plug, "1.5.9", "4f66fd46aecf969b349dd94853e6132db6d832ae6a4b951312b6926ad4ee7ca3", [:mix], [{:absinthe, "~> 1.7", [hex: :absinthe, repo: "hexpm", optional: false]}, {:plug, "~> 1.4", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "dcdc84334b0e9e2cd439bd2653678a822623f212c71088edf0a4a7d03f1fa225"}, + "benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}, {:statistex, "~> 1.0", [hex: :statistex, repo: "hexpm", optional: false]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"}, + "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, + "cowboy": {:hex, :cowboy, "2.13.0", "09d770dd5f6a22cc60c071f432cd7cb87776164527f205c5a6b0f24ff6b38990", [:make, :rebar3], [{:cowlib, ">= 2.14.0 and < 3.0.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, ">= 1.8.0 and < 3.0.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "e724d3a70995025d654c1992c7b11dbfea95205c047d86ff9bf1cda92ddc5614"}, "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"}, - "cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"}, - "credo": {:hex, :credo, "1.6.5", "330ca591c12244ab95498d8f47994c493064b2689febf1236d43d596b4f2261d", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "101de53e6907397c3246ccd2cc9b9f0d3fc0b7805b8e1c1c3d818471fc85bafd"}, - "decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"}, + "cowlib": {:hex, :cowlib, "2.15.0", "3c97a318a933962d1c12b96ab7c1d728267d2c523c25a5b57b0f93392b6e9e25", [:make, :rebar3], [], "hexpm", "4f00c879a64b4fe7c8fcb42a4281925e9ffdb928820b03c3ad325a617e857532"}, + "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, + "decimal": {:hex, :decimal, "2.3.0", "3ad6255aa77b4a3c4f818171b12d237500e63525c2fd056699967a3e7ea20f62", [:mix], [], "hexpm", "a4d66355cb29cb47c3cf30e71329e58361cfcb37c34235ef3bf1d7bf3773aeac"}, "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, - "dialyxir": {:hex, :dialyxir, "1.2.0", "58344b3e87c2e7095304c81a9ae65cb68b613e28340690dfe1a5597fd08dec37", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "61072136427a851674cab81762be4dbeae7679f85b1272b6d25c3a839aff8463"}, - "earmark_parser": {:hex, :earmark_parser, "1.4.26", "f4291134583f373c7d8755566122908eb9662df4c4b63caa66a0eabe06569b0a", [:mix], [], "hexpm", "48d460899f8a0c52c5470676611c01f64f3337bad0b26ddab43648428d94aabc"}, + "dialyxir": {:hex, :dialyxir, "1.4.6", "7cca478334bf8307e968664343cbdb432ee95b4b68a9cba95bdabb0ad5bdfd9a", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "8cf5615c5cd4c2da6c501faae642839c8405b49f8aa057ad4ae401cb808ef64d"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.44", "f20830dd6b5c77afe2b063777ddbbff09f9759396500cdbe7523efd58d7a339c", [:mix], [], "hexpm", "4778ac752b4701a5599215f7030989c989ffdc4f6df457c5f36938cc2d2a2750"}, "eljiffy": {:hex, :eljiffy, "1.3.0", "7e584be454c5ec3fc3ae472eedb4cb2185e9ed6cd863df383ef601de3f3b27fd", [:mix], [{:jiffy, "~> 1.0", [hex: :jiffy, repo: "hexpm", optional: false]}], "hexpm", "90420512d60fb45bc9c09221b4d89cc539c9bfefc1c62f24cb3e2cb13acf2215"}, - "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, - "ex_doc": {:hex, :ex_doc, "0.28.4", "001a0ea6beac2f810f1abc3dbf4b123e9593eaa5f00dd13ded024eae7c523298", [:mix], [{:earmark_parser, "~> 1.4.19", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "bf85d003dd34911d89c8ddb8bda1a958af3471a274a4c2150a9c01c78ac3f8ed"}, - "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, + "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, + "ex_doc": {:hex, :ex_doc, "0.38.3", "ddafe36b8e9fe101c093620879f6604f6254861a95133022101c08e75e6c759a", [:mix], [{:earmark_parser, "~> 1.4.44", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "ecaa785456a67f63b4e7d7f200e8832fa108279e7eb73fd9928e7e66215a01f9"}, + "file_system": {:hex, :file_system, "1.1.0", "08d232062284546c6c34426997dd7ef6ec9f8bbd090eb91780283c9016840e8f", [:mix], [], "hexpm", "bfcf81244f416871f2a2e15c1b515287faa5db9c6bcf290222206d120b3d43f6"}, "gun": {:hex, :gun, "1.3.3", "cf8b51beb36c22b9c8df1921e3f2bc4d2b1f68b49ad4fbc64e91875aa14e16b4", [:rebar3], [{:cowlib, "~> 2.7.0", [hex: :cowlib, repo: "hexpm", optional: false]}], "hexpm", "3106ce167f9c9723f849e4fb54ea4a4d814e3996ae243a1c828b256e749041e0"}, - "jason": {:hex, :jason, "1.3.0", "fa6b82a934feb176263ad2df0dbd91bf633d4a46ebfdffea0c8ae82953714946", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "53fc1f51255390e0ec7e50f9cb41e751c260d065dcba2bf0d08dc51a4002c2ac"}, - "jiffy": {:hex, :jiffy, "1.1.1", "aca10f47aa91697bf24ab9582c74e00e8e95474c7ef9f76d4f1a338d0f5de21b", [:rebar3], [], "hexpm", "62e1f0581c3c19c33a725c781dfa88410d8bff1bbafc3885a2552286b4785c4c"}, - "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, - "makeup_elixir": {:hex, :makeup_elixir, "0.16.0", "f8c570a0d33f8039513fbccaf7108c5d750f47d8defd44088371191b76492b0b", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "28b2cbdc13960a46ae9a8858c4bebdec3c9a6d7b4b9e7f4ed1502f8159f338e7"}, - "makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"}, - "markdown_formatter": {:hex, :markdown_formatter, "0.5.0", "0e582abeecff768cf76ff42e4bbe943d7215bc0eb8c1b0d491d6b12856a0b6d0", [:mix], [{:earmark_parser, "~> 1.4", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "ef52edf96d34e9130eccb206bf6c970bff4b7b2214fa2621f933aaf0dbc76774"}, - "mime": {:hex, :mime, "2.0.2", "0b9e1a4c840eafb68d820b0e2158ef5c49385d17fb36855ac6e7e087d4b1dcc5", [:mix], [], "hexpm", "e6a3f76b4c277739e36c2e21a2c640778ba4c3846189d5ab19f97f126df5f9b7"}, + "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, + "jiffy": {:hex, :jiffy, "1.1.2", "a9b6c9a7ec268e7cf493d028f0a4c9144f59ccb878b1afe42841597800840a1b", [:rebar3], [], "hexpm", "bb61bc42a720bbd33cb09a410e48bb79a61012c74cb8b3e75f26d988485cf381"}, + "makeup": {:hex, :makeup, "1.2.1", "e90ac1c65589ef354378def3ba19d401e739ee7ee06fb47f94c687016e3713d1", [:mix], [{:nimble_parsec, "~> 1.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "d36484867b0bae0fea568d10131197a4c2e47056a6fbe84922bf6ba71c8d17ce"}, + "makeup_elixir": {:hex, :makeup_elixir, "1.0.1", "e928a4f984e795e41e3abd27bfc09f51db16ab8ba1aebdba2b3a575437efafc2", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "7284900d412a3e5cfd97fdaed4f5ed389b8f2b4cb49efc0eb3bd10e2febf9507"}, + "makeup_erlang": {:hex, :makeup_erlang, "1.0.2", "03e1804074b3aa64d5fad7aa64601ed0fb395337b982d9bcf04029d68d51b6a7", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "af33ff7ef368d5893e4a267933e7744e46ce3cf1f61e2dccf53a111ed3aa3727"}, + "markdown_formatter": {:hex, :markdown_formatter, "0.6.0", "bc822cf262f74a70dd6c76d76407b94cd19e59ee6b83248c728d00f7e75f2bd4", [:mix], [{:earmark_parser, "~> 1.4", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "8181c6c1516061de482e24fa69e287878bab88249dae4ca489d89e914040da90"}, + "mime": {:hex, :mime, "2.0.7", "b8d739037be7cd402aee1ba0306edfdef982687ee7e9859bee6198c1e7e2f128", [:mix], [], "hexpm", "6171188e399ee16023ffc5b76ce445eb6d9672e2e241d2df6050f3c771e80ccd"}, "mix_audit": {:hex, :mix_audit, "1.0.1", "9dd114408961b8db214f42fee40b2f632ecd7e4fd29500403068c82c77db8361", [:make, :mix], [{:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.8.0", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "65066bb7757078aa49faaa2f7c1e2d52f56ff6fe6cff01723dbaf5be2a75771b"}, - "nimble_parsec": {:hex, :nimble_parsec, "1.2.3", "244836e6e3f1200c7f30cb56733fd808744eca61fd182f731eac4af635cc6d0b", [:mix], [], "hexpm", "c8d789e39b9131acf7b99291e93dae60ab48ef14a7ee9d58c6964f59efb570b0"}, - "phoenix": {:hex, :phoenix, "1.6.11", "29f3c0fd12fa1fc4d4b05e341578e55bc78d96ea83a022587a7e276884d397e4", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "1664e34f80c25ea4918fbadd957f491225ef601c0e00b4e644b1a772864bfbc2"}, - "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.1", "ba04e489ef03763bf28a17eb2eaddc2c20c6d217e2150a61e3298b0f4c2012b5", [:mix], [], "hexpm", "81367c6d1eea5878ad726be80808eb5a787a23dee699f96e72b1109c57cdd8d9"}, - "phoenix_view": {:hex, :phoenix_view, "1.1.2", "1b82764a065fb41051637872c7bd07ed2fdb6f5c3bd89684d4dca6e10115c95a", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "7ae90ad27b09091266f6adbb61e1d2516a7c3d7062c6789d46a7554ec40f3a56"}, - "plug": {:hex, :plug, "1.13.6", "187beb6b67c6cec50503e940f0434ea4692b19384d47e5fdfd701e93cadb4cc2", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "02b9c6b9955bce92c829f31d6284bf53c591ca63c4fb9ff81dfd0418667a34ff"}, - "plug_cowboy": {:hex, :plug_cowboy, "2.5.2", "62894ccd601cf9597e2c23911ff12798a8a18d237e9739f58a6b04e4988899fe", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "ea6e87f774c8608d60c8d34022a7d073bd7680a0a013f049fc62bf35efea1044"}, - "plug_crypto": {:hex, :plug_crypto, "1.2.2", "05654514ac717ff3a1843204b424477d9e60c143406aa94daf2274fdd280794d", [:mix], [], "hexpm", "87631c7ad914a5a445f0a3809f99b079113ae4ed4b867348dd9eec288cecb6db"}, - "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, - "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, - "telemetry": {:hex, :telemetry, "1.1.0", "a589817034a27eab11144ad24d5c0f9fab1f58173274b1e9bae7074af9cbee51", [:rebar3], [], "hexpm", "b727b2a1f75614774cff2d7565b64d0dfa5bd52ba517f16543e6fc7efcc0df48"}, + "nimble_parsec": {:hex, :nimble_parsec, "1.4.2", "8efba0122db06df95bfaa78f791344a89352ba04baedd3849593bfce4d0dc1c6", [:mix], [], "hexpm", "4b21398942dda052b403bbe1da991ccd03a053668d147d53fb8c4e0efe09c973"}, + "phoenix": {:hex, :phoenix, "1.8.1", "865473a60a979551a4879db79fbfb4503e41cd809e77c85af79716578b6a456d", [:mix], [{:bandit, "~> 1.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "84d77d2b2e77c3c7e7527099bd01ef5c8560cd149c036d6b3a40745f11cd2fb2"}, + "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"}, + "phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"}, + "plug": {:hex, :plug, "1.18.1", "5067f26f7745b7e31bc3368bc1a2b818b9779faa959b49c934c17730efc911cf", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "57a57db70df2b422b564437d2d33cf8d33cd16339c1edb190cd11b1a3a546cc2"}, + "plug_cowboy": {:hex, :plug_cowboy, "2.7.4", "729c752d17cf364e2b8da5bdb34fb5804f56251e88bb602aff48ae0bd8673d11", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "9b85632bd7012615bae0a5d70084deb1b25d2bcbb32cab82d1e9a1e023168aa3"}, + "plug_crypto": {:hex, :plug_crypto, "2.1.1", "19bda8184399cb24afa10be734f84a16ea0a2bc65054e23a62bb10f06bc89491", [:mix], [], "hexpm", "6470bce6ffe41c8bd497612ffde1a7e4af67f36a15eea5f921af71cf3e11247c"}, + "ranch": {:hex, :ranch, "2.2.0", "25528f82bc8d7c6152c57666ca99ec716510fe0925cb188172f41ce93117b1b0", [:make, :rebar3], [], "hexpm", "fa0b99a1780c80218a4197a59ea8d3bdae32fbff7e88527d7d8a4787eff4f8e7"}, + "statistex": {:hex, :statistex, "1.1.0", "7fec1eb2f580a0d2c1a05ed27396a084ab064a40cfc84246dbfb0c72a5c761e5", [:mix], [], "hexpm", "f5950ea26ad43246ba2cce54324ac394a4e7408fdcf98b8e230f503a0cba9cf5"}, + "telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"}, + "websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"}, + "websock_adapter": {:hex, :websock_adapter, "0.5.8", "3b97dc94e407e2d1fc666b2fb9acf6be81a1798a2602294aac000260a7c4a47d", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "315b9a1865552212b5f35140ad194e67ce31af45bcee443d4ecb96b5fd3f3782"}, "yamerl": {:hex, :yamerl, "0.10.0", "4ff81fee2f1f6a46f1700c0d880b24d193ddb74bd14ef42cb0bcf46e81ef2f8e", [:rebar3], [], "hexpm", "346adb2963f1051dc837a2364e4acf6eb7d80097c0f53cbdc3046ec8ec4b4e6e"}, "yaml_elixir": {:hex, :yaml_elixir, "2.8.0", "c7ff0034daf57279c2ce902788ce6fdb2445532eb4317e8df4b044209fae6832", [:mix], [{:yamerl, "~> 0.8", [hex: :yamerl, repo: "hexpm", optional: false]}], "hexpm", "4b674bd881e373d1ac6a790c64b2ecb69d1fd612c2af3b22de1619c15473830b"}, } diff --git a/test/integration/socket_test.exs b/test/integration/socket_test.exs index eba8b48..ff18376 100644 --- a/test/integration/socket_test.exs +++ b/test/integration/socket_test.exs @@ -10,11 +10,8 @@ defmodule Absinthe.GraphqlWS.SocketTest do def send_connection_init(%{client: client}) do :ok = Test.Client.push(client, %{type: "connection_init"}) - assert {:ok, - [ - {:text, Jason.encode!(%{"type" => "connection_ack", "payload" => %{}})} - ]} == - Test.Client.get_new_replies(client) + assert {:ok, [{:text, json}]} = Test.Client.get_new_replies(client) + assert Jason.decode!(json) == %{"type" => "connection_ack", "payload" => %{}} :ok end @@ -33,7 +30,7 @@ defmodule Absinthe.GraphqlWS.SocketTest do defp assert_json_received(client, payload) do assert {:ok, [{:text, json}]} = Test.Client.get_new_replies(client) - assert json == Jason.encode!(payload) + assert Jason.decode!(json) == payload end describe "initalization" do diff --git a/test/support/test/client.ex b/test/support/test/client.ex index 00b86c1..08fa800 100644 --- a/test/support/test/client.ex +++ b/test/support/test/client.ex @@ -129,5 +129,5 @@ defmodule Test.Client do end defp debug(msg), do: Logger.debug("[client@#{inspect(self())}] #{msg}") - defp warn(msg), do: Logger.warn("[client@#{inspect(self())}] #{msg}") + defp warn(msg), do: Logger.warning("[client@#{inspect(self())}] #{msg}") end diff --git a/test/support/test/site.ex b/test/support/test/site.ex index c21cf9f..81b73bb 100644 --- a/test/support/test/site.ex +++ b/test/support/test/site.ex @@ -117,7 +117,7 @@ defmodule Test.Site do defp pubsub_name, do: - Application.get_env(:absinthe_graphql_ws, Test.Site.Endpoint) + Elixir.Application.get_env(:absinthe_graphql_ws, Test.Site.Endpoint) |> Keyword.fetch!(:pubsub_server) end