Skip to content

Commit cf8b44b

Browse files
authored
Fix Phoenix.ChannelTest sockets violating Phoenix.Socket.t (#6870)
* Type topic and channel_pid as nilable in Phoenix.Socket.t Both fields are nil until a channel is joined: Socket.user_connect builds the socket that Channel.Server.join/4 receives with neither set. The spec on Server.join/4 required a binary topic and a pid, so any caller passing an unjoined socket broke the contract. * Keep the ChannelTest supervisor in socket.private Phoenix.ChannelTest stored its test supervisor in the transport field as {Phoenix.ChannelTest, sup}, but Phoenix.Socket.t types transport as an atom. Dialyzer then reported every test join as never returning. The transport is now Phoenix.ChannelTest and the supervisor is kept in socket.private, which channel join preserves, so sockets returned from join/4 can still be used to join again. Closes #5509.
1 parent 2b12377 commit cf8b44b

4 files changed

Lines changed: 20 additions & 7 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Changelog for v1.9
22

3+
## Bug fixes
4+
5+
* [Phoenix.ChannelTest] Fix test sockets violating the Phoenix.Socket.t
6+
typespec, which made Dialyzer treat every test join as never returning
7+
([#5509](https://github.com/phoenixframework/phoenix/issues/5509))
8+
* [Phoenix.Socket] Type `topic` and `channel_pid` as possibly `nil` in
9+
`Phoenix.Socket.t`, as they are before a channel is joined
10+
311
## Enhancements
412

513
* The longpoll session token is now sent in a `x-phoenix-longpoll-token`

‎lib/phoenix/socket.ex‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ defmodule Phoenix.Socket do
275275
@type t :: %Socket{
276276
assigns: map,
277277
channel: atom,
278-
channel_pid: pid,
278+
channel_pid: pid | nil,
279279
endpoint: atom,
280280
handler: atom,
281281
id: String.t() | nil,
@@ -284,7 +284,7 @@ defmodule Phoenix.Socket do
284284
private: map,
285285
pubsub_server: atom,
286286
serializer: atom,
287-
topic: String.t(),
287+
topic: String.t() | nil,
288288
transport: atom,
289289
transport_pid: pid
290290
}

‎lib/phoenix/test/channel_test.ex‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,8 @@ defmodule Phoenix.ChannelTest do
261261
id: id,
262262
pubsub_server: endpoint.config(:pubsub_server),
263263
serializer: NoopSerializer,
264-
transport: {__MODULE__, fetch_test_supervisor!(options)},
264+
private: %{phoenix_test_supervisor: fetch_test_supervisor!(options)},
265+
transport: __MODULE__,
265266
transport_pid: self()
266267
}
267268
end
@@ -335,17 +336,19 @@ defmodule Phoenix.ChannelTest do
335336
Keyword.pop(options, :connect_info, %{})
336337
end
337338

339+
sup = fetch_test_supervisor!(options)
340+
338341
map = %{
339342
endpoint: endpoint,
340-
transport: {__MODULE__, fetch_test_supervisor!(options)},
343+
transport: __MODULE__,
341344
options: [serializer: [{NoopSerializer, "~> 1.0.0"}]],
342345
params: __stringify__(params),
343346
connect_info: connect_info
344347
}
345348

346349
with {:ok, state} <- handler.connect(map),
347350
{:ok, {_, socket}} = handler.init(state),
348-
do: {:ok, socket}
351+
do: {:ok, %{socket | private: Map.put(socket.private, :phoenix_test_supervisor, sup)}}
349352
end
350353

351354
@doc "See `subscribe_and_join!/4`."
@@ -441,7 +444,7 @@ defmodule Phoenix.ChannelTest do
441444
match_topic_to_channel!(socket, topic)
442445
end
443446

444-
%Socket{transport: {__MODULE__, sup}} = socket
447+
%Socket{private: %{phoenix_test_supervisor: sup}} = socket
445448

446449
starter =
447450
fn _, _, spec ->

‎test/phoenix/test/channel_test.exs‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,11 +234,12 @@ defmodule Phoenix.Test.ChannelTest do
234234
assert socket.endpoint == @endpoint
235235
assert socket.pubsub_server == Phoenix.Test.ChannelTest.PubSub
236236
assert socket.topic == "foo:socket"
237-
assert {Phoenix.ChannelTest, _} = socket.transport
237+
assert socket.transport == Phoenix.ChannelTest
238238
assert socket.transport_pid == self()
239239
assert socket.serializer == Phoenix.ChannelTest.NoopSerializer
240240
assert socket.assigns == %{hello: :world, original: :assign}
241241
assert %{socket | joined: true} == client
242+
assert {:ok, _, _} = join(client, Channel, "foo:socket")
242243

243244
{:links, links} = Process.info(self(), :links)
244245
assert client.channel_pid in links
@@ -366,6 +367,7 @@ defmodule Phoenix.Test.ChannelTest do
366367
test "connects and joins topics directly" do
367368
:error = connect(UserSocket, %{"reject" => true})
368369
{:ok, socket} = connect(UserSocket, %{})
370+
assert socket.transport == Phoenix.ChannelTest
369371
socket = subscribe_and_join!(socket, "foo:ok")
370372
push(socket, "broadcast", %{"foo" => "bar"})
371373
assert socket.id == "123"

0 commit comments

Comments
 (0)