数据库所有权过程错误在容器化的灵药1.6.1中运行phoenix测试

时间:2018-03-26 23:11:21

标签: docker elixir ecto drone

我有一个伞形项目由:

组成
  • 网关 - 凤凰应用
  • 核心 - 业务模型层通知专用应用程序,用于提供短信,电子邮件等...用户
  • 用户管理,角色系统和身份验证。

这三个组件通过AMQP连接,因此它们可以在它们之间发送和接收消息。

我们正在使用Docker,并且在google cloud的kubernetes引擎上托管了drone.io。所以,正在发生的是随机应用程序在运行我的测试时引发以下异常:

import com.vaadin.ui.*;

import java.util.function.Consumer;

// confirmation window
public class ConfirmationWindow {
    private Integer value;

    public ConfirmationWindow(Integer value) {
        this.value = value;
    }

    public void showModal(Consumer<Boolean> resultCallback) {
        Window window = new Window("Confirm transaction");
        window.setContent(
                new VerticalLayout(
                        new Label("Your account will be charged with " + (value / 100) + " for this transaction, are you sure you want to continue?"),
                        new HorizontalLayout(
                                new Button("Ok", event -> {
                                    resultCallback.accept(true);
                                    window.close();
                                }),
                                new Button("Cancel", event -> {
                                    resultCallback.accept(false);
                                    window.close();
                                })
                        )
                )
        );
        window.setModal(true);
        getUI().addWindow(window);
    }
}

这是一个Json,因为我们在测试中交换了amqp消息,例如:

import com.vaadin.data.Binder;
import com.vaadin.data.converter.StringToIntegerConverter;
import com.vaadin.ui.*;

public class TransactionForm extends FormLayout {

    private static final String FEE_ACCEPTED_MESSAGE = "Press the save button to view the transaction fee and confirm";

    // initial withdrawal mount
    private Integer value = 0;
    // used to make binder "invalid" until confirmation dialog is closed with "Ok"
    private Boolean customerAcceptedAtmFee = false;

    public TransactionForm() {
        // some existing bean (eg, loaded from DB for editing)
        BankAccount bean = new BankAccount(1000);

        // form components
        TextField currentAmount = new TextField("Available");
        TextField withdrawalAmount = new TextField("Withdraw");

        // binder setup
        Binder<BankAccount> accountBinder = new Binder<>(BankAccount.class);
        Label statusLabel = new Label();
        accountBinder.setStatusLabel(statusLabel);

        // consider valid only if the client has also accepted to pay the fee
        accountBinder.withValidator(bankAccount -> customerAcceptedAtmFee, FEE_ACCEPTED_MESSAGE);

        // current amount
        accountBinder.forField(currentAmount)
                .withConverter(new StringToIntegerConverter("Whatever"))
                .bind(BankAccount::getCurrentAmount, null);

        // withdrawal amount
        accountBinder.forField(withdrawalAmount)
                .withConverter(new StringToIntegerConverter("Please enter a valid value"))
                .withValidator(bean::hasEnoughMoneyForWithdrawal, "Not enough money")
                .withValidator(value -> value > 0, "Please select a value greater than 0")
                .asRequired("Please select withdrawal amount")
                .bind(bankAccount -> TransactionForm.this.value, (bankAccount, value) -> TransactionForm.this.value = value);

        // bind to bean
        accountBinder.setBean(bean);

        // show the modal and assign the call-back logic
        Button saveButton = new Button("Save", event -> new ConfirmationWindow(this, Integer.valueOf(withdrawalAmount.getValue())).showModal(value -> {
            // whether the client selected yes or no
            customerAcceptedAtmFee = value;

            // if all data selected, and client pressed "Ok", then execute the transaction
            if (accountBinder.validate().isOk()) {
                removeAllComponents();
                addComponent(new Label("Transaction executed"));
            }
        }));

        // disable the save button by default and enable it if
        // the only validation error is the fact that the use has not yet accepted the fee
        saveButton.setEnabled(false);
        accountBinder.addStatusChangeListener(event -> {
            saveButton.setEnabled(accountBinder.getStatusLabel().get().getValue().equals(FEE_ACCEPTED_MESSAGE));
        });

        // add fields to the UI
        addComponents(currentAmount, withdrawalAmount, statusLabel, saveButton);
    }
}

详细说明我的.drone.yaml文件:

{\"status\":\"error\",\"message\":\"%DBConnection.OwnershipError{message: \\\"cannot find ownership process for #PID<0.716.0>.\\\\n\\\\nWhen using ownership, you must manage connections in one\\\\nof the four ways:\\\\n\\\\n* By explicitly checking out a connection\\\\n* By explicitly allowing a spawned process\\\\n* By running the pool in shared mode\\\\n* By using :caller option with allowed process\\\\n\\\\nThe first two options require every new process to explicitly\\\\ncheck a connection out or be allowed by calling checkout or\\\\nallow respectively.\\\\n\\\\nThe third option requires a {:shared, pid} mode to be set.\\\\nIf using shared mode in tests, make sure your tests are not\\\\nasync.\\\\n\\\\nThe fourth option requires [caller: pid] to be used when\\\\nchecking out a connection from the pool. The caller process\\\\nshould already be allowed on a connection.\\\\n\\\\nIf you are reading this error, it means you have not done one\\\\nof the steps above or that the owner process has crashed.\\\\n\\\\nSee Ecto.Adapters.SQL.Sandbox docs for more information.\\\"}\",\"code\":0}"
每个应用中的

# Given the module FindUserByEmail def Users.Services.FindUserByEmail do use GenAMQP.Server, event: "find_user_by_email", conn_name: Application.get_env(:gen_amqp, :conn_name) alias User.Repo alias User.Models.User, as: UserModel def execute(payload) do %{ "email" => email } = Poison.decode!(payload) resp = case Repo.get_by(UserModel, email: email) do %UserModel{} = user -> %{status: :ok, response: user} nil -> ErrorHelper.err(2011) true -> ErrorHelper.err(2012) {:error, %Ecto.Changeset{} = changeset} -> ViewHelper.translate_errors(changeset) end {:reply, Poison.encode!(resp)} end end # and the test defmodule Users.Services.FindUserByEmailTest do use User.ModelCase alias GenAMQP.Client def execute(payload) do resp = Client.call_with_conn(@conn_name, "find_user_by_email", payload) data = Poison.decode!(resp, keys: :atoms) assert data.status == "ok" end end 文件都包含以下别名

pipeline:
unit-tests:
image: bitwalker/alpine-elixir-phoenix:1.6.1
environment:
    RABBITCONN: amqp://user:pass@localhost:0000/unit_testing
    DATABASE_URL: ecto://username:password@postgres/testing
commands:
    - mix local.hex --force && mix local.rebar --force
    - mix deps.get
    - mix compile --force
    - mix test

我们所有mix.exs个文件都包含以下配置:

defp aliases do
    [
        "test": ["ecto.create", "ecto.migrate", "test"]
    ]
end

我该如何调试?它只在测试容器内的代码时发生。这个问题会与集装箱的资源有关吗?

任何提示或提示都将受到赞赏。

1 个答案:

答案 0 :(得分:0)

尝试将onwership_timeouttimeout设置为config/tests.exs

中的大数字
config :app_name, User.Repo,
adapter: Ecto.Adapters.Postgres,
  username: ...,
  password: ...,
  database: ...,
  hostname: ...,
  pool: Ecto.Adapters.SQL.Sandbox,
  timeout: 120_000, # i think the default is 5000
  pool_timeout: 120_000,
  ownership_timeout: 120_000 #i think the default is 5000