2016-07-12 2 views
6

Недавно я обновил проект phoenix до Ecto 2.0.2. У меня есть код, который использует Task.Supervisor.async_nolink, чтобы сделать некоторые обновления для db в своем потоке. Я получаю следующее сообщение об ошибке, когда мои тесты запуска (происходит только на моих тестах)Ecto 2.0 SQL Sandbox Ошибка при тестах

[error] Postgrex.Protocol (#PID<0.XXX.0>) disconnected: ** 
(DBConnection.ConnectionError) owner #PID<0.XXX.0> exited while 
client #PID<0.XXX.0> is still running with: shutdown 

Теперь я думаю я понимаю Что происходит: Подключение бассейна Ecto Песочница проверяется назад прежде, чем сделка дб завершена , Согласно документам (по крайней мере, так, как я их читал), способ обойти это - использовать общий пул соединений: Ecto.Adapters.SQL.Sandbox.mode(MyApp.Repo, {:shared, self()}), который я делаю. К сожалению, это не работает.

Как настроить мои тесты, чтобы эта ошибка не возникала?

ответ

3

Если кто-то сталкивается с этим, я получил ответ обратно на это прямо с языка автора Хосе Valim:

Да, ваше понимание этого вопроса является правильным. Это происходит потому, что тестовый процесс, тот, кто владеет соединением, вышел, но Task по-прежнему использует его соединение. Использование {: shared, self()} не исправляет его, потому что тест по-прежнему владеет соединением, вы просто делитесь им неявно.

Способ исправления состоит в том, чтобы гарантировать, что Задача завершилась до завершения теста. Это можно сделать, вызвав Process.exit (task_pid,: kill). Если вы не знаете PID задачи, вы можете вызвать Task.Supervisor.which_children (NameOfYourTaskSupervisor), чтобы вернуть все PID, которые вы затем проходите и убиваете. Однако, если вы сделаете такой подход, тест не может выполняться одновременно (так как вы можете убить задачи, запущенные другим тестом).

+1

TLDR: нет решения. – Noma4i

+0

Спасибо за сообщение о том, что было найдено. Я использовал отзывы Хосе, чтобы решить проблему для меня. Таким образом, это решение. –

3

У меня была такая же проблема сегодня, и я думаю, что нашел возможное решение, позволяющее проводить тесты одновременно.

Я использую описанную здесь методику: http://blog.plataformatec.com.br/2015/10/mocks-and-explicit-contracts/ для замены Task.Supervisor при выполнении тестов.

Вместо:

Task.Supervisor.async_nolink(TaskSupervisor, fn -> (...) end) 

Я делаю:

@task_supervisor Application.get_env(:app, :task_supervisor) || Task.Supervisor 
# ... 
@task_supervisor.async_nolink(TaskSupervisor, fn -> (...) end) 

, а затем я определяю TestTaskSupervisor

defmodule TestTaskSupervisor do 
    def async_nolink(_, fun), do: fun.() 
end 

и добавить config :app, :task_supervisor, TestTaskSupervisor в config/test.exs.

Таким образом, я уверен, что задача будет выполняться синхронно и заканчиваться перед тестовым процессом.

Смежные вопросы