Почему таблица ets переживает ct:init_per_testcase, а не init_per_suite?

У меня есть общий набор тестов, который пытается создать таблицу ets для использования во всех наборах и во всех тестах. Это выглядит так:

-module(an_example_SUITE).
-include_lib("common_test/include/ct.hrl").

-compile(export_all).

all() -> [ets_tests].

init_per_suite(Config) ->
    TabId = ets:new(conns, [set]),
    ets:insert(TabId, {foo, 2131}),
    [{table,TabId} | Config].

end_per_suite(Config) ->
    ets:delete(?config(table, Config)).

ets_tests(Config) ->
    TabId = ?config(table, Config),
    [{foo, 2131}] = ets:lookup(TabId, foo).

ets_tests Сбой функции со значком. Создание / уничтожение таблицы ets для каждого теста, которая выглядит так:

-module(an_example_SUITE).
-include_lib("common_test/include/ct.hrl").

-compile(export_all).

all() -> [ets_tests].

init_per_testcase(Config) ->
    TabId = ets:new(conns, [set]),
    ets:insert(TabId, {foo, 2131}),
    [{table,TabId} | Config].

end_per_testcase(Config) ->
    ets:delete(?config(table, Config)).

ets_tests(Config) ->
    TabId = ?config(table, Config),
    [{foo, 2131}] = ets:lookup(TabId, foo).

Запустив это, я обнаружил, что это прекрасно работает.

Я смущен этим поведением и не могу определить, почему это произойдет, формируя документы. Вопросы:

  • Почему это происходит?
  • Как я могу иметь таблицу ets для совместного использования для каждого набора и для каждого теста?

2 ответа

Решение

Как уже упоминалось в ответе Паскаля и как обсуждалось только в Руководстве пользователя init_per_testcase а также end_per_testcase запустить в том же процессе, что и тестовый набор. Поскольку таблицы ETS связаны с процессом владельца, единственный способ сохранить таблицу ETS в течение всего набора или группы - это передать ее или определить наследующий процесс.

Вы можете легко создать процесс в своем init_per_suite или же init_per_group функции, установите его в качестве наследника для таблицы ETS и передать его pid в конфигурации.

Чтобы очистить все, что вам нужно, это убить этот процесс в вашем end_per_suite или же end_per_group функции.

-module(an_example_SUITE).
-include_lib("common_test/include/ct.hrl").

-compile(export_all).

all() -> [ets_tests].

ets_owner() ->
    receive
        stop -> exit(normal);
        Any -> ets_owner()
    end.

init_per_suite(Config) ->
    Pid = spawn(fun ets_owner/0),
    TabId = ets:new(conns, [set, protected, {heir, Pid, []}]),
    ets:insert(TabId, {foo, 2131}),
    [{table,TabId},{table_owner, Pid} | Config].

end_per_suite(Config) ->
    ?config(table_owner, Config) ! stop.

ets_tests(Config) ->
    TabId = ?config(table, Config),
    [{foo, 2131}] = ets:lookup(TabId, foo).

Вам также необходимо убедиться, что вы все еще можете получить доступ к своей таблице из процесса тестирования, сделав ее protectedили же public

Таблица ets присоединяется к процессу и уничтожается, как только процесс завершается, если только вы не используете функцию give_away (что, боюсь, в этом случае неосуществимо)

Как и состояние в общем документе tets, каждый тестовый пример, init_per_suite и end_per_suite выполняются в отдельных процессах, поэтому таблица ets уничтожается, как только вы выходите из функции init_per_suite.

fron common_test doc

init_per_suite и end_per_suite будут выполняться в выделенных процессах Erlang, как это делают тестовые примеры. Однако результат этих функций не включается в статистику успешных, неудачных и пропущенных испытаний.

от ETS DOC

Владельцем по умолчанию является процесс, который создал таблицу. Владение таблицей может быть передано при завершении процесса с помощью опции наследника или явным образом путем вызова give_away/3.

Другие вопросы по тегам