<commit_before>%% -------------------------------------------------------------------
%%
%% Copyright (c) 2010 <NAME>.  All Rights Reserved.
%%
%% This file is provided to you under the Apache License,
%% Version 2.0 (the "License"); you may not use this file
%% except in compliance with the License.  You may obtain
%% a copy of the License at
%%
%%   http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing,
%% software distributed under the License is distributed on an
%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
%% KIND, either express or implied.  See the License for the
%% specific language governing permissions and limitations
%% under the License.
%%
%% -------------------------------------------------------------------

-module(prop_partisan_paxoid).

-author("<NAME> <<EMAIL>>").

-include("partisan.hrl").

-include_lib("proper/include/proper.hrl").

-compile([export_all]).

-define(PERFORM_SUMMARY, false).

-define(GROUP, paxoid).

%%%===================================================================
%%% Generators
%%%===================================================================

node_name() ->
    oneof(names()).

names() ->
    NameFun = fun(N) -> 
        list_to_atom("node_" ++ integer_to_list(N)) 
    end,
    lists:map(NameFun, lists:seq(1, ?TEST_NUM_NODES)).

%%%===================================================================
%%% Node Functions
%%%===================================================================

-record(node_state, {counter}).

%% What node-specific operations should be called.
node_commands() ->
    [{call, ?MODULE, next_id, [node_name()]}].

%% Assertion commands.
node_assertion_functions() ->
    [max_id].

%% Global functions.
node_global_functions() ->
    [max_id].

%% What should the initial node state be.
node_initial_state() ->
    node_debug("initializing", []),
    #node_state{counter=0}.

%% Names of the node functions so we kow when we can dispatch to the node
%% pre- and postconditions.
node_functions() ->
    lists:map(fun({call, _Mod, Fun, _Args}) -> Fun end, node_commands()).

%% Precondition.
node_precondition(_NodeState, {call, ?MODULE, next_id, [_Node]}) ->
    true;
node_precondition(_NodeState, _Command) ->
    false.

%% Next state.
node_next_state(_State, #node_state{counter=Counter}=NodeState, _Value, {call, ?MODULE, next_id, [_Node]}) ->
    NodeState#node_state{counter=Counter+1};
node_next_state(_State, NodeState, _Response, _Command) ->
    NodeState.

%% Postconditions for node commands.
node_postcondition(#node_state{counter=_Counter}, {call, ?MODULE, max_id, []}, Results) ->
    node_debug("postcondition received ~p from max_id", [Results]),

    % lists:all(fun({Node, Result}) -> 
    %     case Counter =:= Result of
    %         true ->
    %             true;
    %         false ->
    %             node_debug("=> node: ~p has wrong value: ~p, should be ~p", [Node, Result, Counter]),
    %             false
    %     end
    % end, Results);

    true;
node_postcondition(_NodeState, {call, ?MODULE, next_id, [_Node]}, {badrpc,timeout}) ->
    true;
node_postcondition(#node_state{counter=Counter}, {call, ?MODULE, next_id, [_Node]}, Value) ->
    node_debug("postcondition received ~p from next_id when value should be: ~p", [Value, Counter]),
    Counter + 1 =:= Value;
node_postcondition(_NodeState, Command, Response) ->
    node_debug("generic postcondition fired (this probably shouldn't be hit) for command: ~p with response: ~p", 
               [Command, Response]),
    false.

%%%===================================================================
%%% Commands
%%%===================================================================

-define(PROPERTY_MODULE, prop_partisan).

-define(TABLE, table).
-define(RECEIVER, receiver).

-define(ETS, prop_partisan).
-define(NAME, fun(Name) -> [{_, NodeName}] = ets:lookup(?ETS, Name), NodeName end).

%% @private
next_id(Node) ->
    ?PROPERTY_MODULE:command_preamble(Node, [next_id]),

    Result = rpc:call(?NAME(Node), paxoid, next_id, [?GROUP], 5000),

    ?PROPERTY_MODULE:command_conclusion(Node, [next_id]),

    Result.

%% @private
max_id() ->
    node_debug("executing max_id command", []),

    RunnerNode = node(),

    ?PROPERTY_MODULE:command_preamble(RunnerNode, [max_id]),

    Results = lists:map(fun(Node) ->
        {ok, Result} = rpc:call(?NAME(Node), paxoid, max_id, [?GROUP], 5000),
        node_debug("result of max_id: ~p~n", [Result]),
        {Node, Result}
    end, names()),

    ?PROPERTY_MODULE:command_conclusion(RunnerNode, [max_id]),

    Results.

%%%===================================================================
%%% Helper Functions
%%%===================================================================

-define(NODE_DEBUG, true).

%% Should we do node debugging?
node_debug(Line, Args) ->
    case ?NODE_DEBUG of
        true ->
            lager:info("~p: " ++ Line, [?MODULE] ++ Args);
        false ->
            ok
    end.

%% @private
loop() ->
    receive
        terminate ->
            ok
    end,
    loop().

%% @private
node_begin_property() ->
    partisan_trace_orchestrator:start_link().

%% @private
node_begin_case() ->
    %% Get nodes.
    [{nodes, Nodes}] = ets:lookup(prop_partisan, nodes),

    %% Enable pid encoding.
    lists:foreach(fun({ShortName, _}) ->
        node_debug("enabling pid_encoding at node ~p", [ShortName]),
        ok = rpc:call(?NAME(ShortName), partisan_config, set, [pid_encoding, true])
    end, Nodes),

    %% Enable register_pid_for_encoding.
    lists:foreach(fun({ShortName, _}) ->
        node_debug("enabling register_pid_for_encoding at node ~p", [ShortName]),
        ok = rpc:call(?NAME(ShortName), partisan_config, set, [register_pid_for_encoding, true])
    end, Nodes),

    %% Load, configure, and start paxoid.
    lists:foreach(fun({ShortName, _}) ->
        node_debug("starting paxoid at node ~p", [ShortName]),
        ok = rpc:call(?NAME(ShortName), application, load, [paxoid]),

        node_debug("configuring paxoid at node ~p", [ShortName]),
        ok = rpc:call(?NAME(ShortName), application, set_env, [paxoid, predefined, [paxoid]]),

        node_debug("starting paxoid at node ~p", [ShortName]),
        {ok, _} = rpc:call(?NAME(ShortName), application, ensure_all_started, [paxoid])
    end, Nodes),

    %% Join.
    OtherNodes = lists:map(fun({ShortName, _}) -> ?NAME(ShortName) end, tl(Nodes)),
    {FirstName, _} = hd(Nodes),
    node_debug("joining all nodes with paxoid to first node: ~p: ~p", [FirstName, OtherNodes]),
    ok = rpc:call(?NAME(FirstName), paxoid, join, [?GROUP, OtherNodes]),

    %% Info.
    node_debug("getting info from paxoid on first node", []),
    {ok, Info} = rpc:call(?NAME(FirstName), paxoid, info, [?GROUP]),
    node_debug("=> info: ~p", [Info]),

    %% Sleep.
    node_debug("sleeping for convergence", []),
    timer:sleep(50000),
    node_debug("done.", []),

    ok.

%% @private
node_end_case() -><commit_msg>Reduce setup time.<commit_after>%% -------------------------------------------------------------------
%%
%% Copyright (c) 2010 <NAME>.  All Rights Reserved.
%%
%% This file is provided to you under the Apache License,
%% Version 2.0 (the "License"); you may not use this file
%% except in compliance with the License.  You may obtain
%% a copy of the License at
%%
%%   http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing,
%% software distributed under the License is distributed on an
%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
%% KIND, either express or implied.  See the License for the
%% specific language governing permissions and limitations
%% under the License.
%%
%% -------------------------------------------------------------------

-module(prop_partisan_paxoid).

-author("<NAME> <<EMAIL>>").

-include("partisan.hrl").

-include_lib("proper/include/proper.hrl").

-compile([export_all]).

-define(PERFORM_SUMMARY, false).

-define(GROUP, paxoid).

%%%===================================================================
%%% Generators
%%%===================================================================

node_name() ->
    oneof(names()).

names() ->
    NameFun = fun(N) -> 
        list_to_atom("node_" ++ integer_to_list(N)) 
    end,
    lists:map(NameFun, lists:seq(1, ?TEST_NUM_NODES)).

%%%===================================================================
%%% Node Functions
%%%===================================================================

-record(node_state, {counter}).

%% What node-specific operations should be called.
node_commands() ->
    [{call, ?MODULE, next_id, [node_name()]}].

%% Assertion commands.
node_assertion_functions() ->
    [max_id].

%% Global functions.
node_global_functions() ->
    [max_id].

%% What should the initial node state be.
node_initial_state() ->
    node_debug("initializing", []),
    #node_state{counter=0}.

%% Names of the node functions so we kow when we can dispatch to the node
%% pre- and postconditions.
node_functions() ->
    lists:map(fun({call, _Mod, Fun, _Args}) -> Fun end, node_commands()).

%% Precondition.
node_precondition(_NodeState, {call, ?MODULE, next_id, [_Node]}) ->
    true;
node_precondition(_NodeState, _Command) ->
    false.

%% Next state.
node_next_state(_State, #node_state{counter=Counter}=NodeState, _Value, {call, ?MODULE, next_id, [_Node]}) ->
    NodeState#node_state{counter=Counter+1};
node_next_state(_State, NodeState, _Response, _Command) ->
    NodeState.

%% Postconditions for node commands.
node_postcondition(#node_state{counter=_Counter}, {call, ?MODULE, max_id, []}, Results) ->
    node_debug("postcondition received ~p from max_id", [Results]),

    % lists:all(fun({Node, Result}) -> 
    %     case Counter =:= Result of
    %         true ->
    %             true;
    %         false ->
    %             node_debug("=> node: ~p has wrong value: ~p, should be ~p", [Node, Result, Counter]),
    %             false
    %     end
    % end, Results);

    true;
node_postcondition(_NodeState, {call, ?MODULE, next_id, [_Node]}, {badrpc,timeout}) ->
    true;
node_postcondition(#node_state{counter=Counter}, {call, ?MODULE, next_id, [_Node]}, Value) ->
    node_debug("postcondition received ~p from next_id when value should be: ~p", [Value, Counter]),
    Counter + 1 =:= Value;
node_postcondition(_NodeState, Command, Response) ->
    node_debug("generic postcondition fired (this probably shouldn't be hit) for command: ~p with response: ~p", 
               [Command, Response]),
    false.

%%%===================================================================
%%% Commands
%%%===================================================================

-define(PROPERTY_MODULE, prop_partisan).

-define(TABLE, table).
-define(RECEIVER, receiver).

-define(ETS, prop_partisan).
-define(NAME, fun(Name) -> [{_, NodeName}] = ets:lookup(?ETS, Name), NodeName end).

%% @private
next_id(Node) ->
    ?PROPERTY_MODULE:command_preamble(Node, [next_id]),

    Result = rpc:call(?NAME(Node), paxoid, next_id, [?GROUP], 5000),

    ?PROPERTY_MODULE:command_conclusion(Node, [next_id]),

    Result.

%% @private
max_id() ->
    node_debug("executing max_id command", []),

    RunnerNode = node(),

    ?PROPERTY_MODULE:command_preamble(RunnerNode, [max_id]),

    Results = lists:map(fun(Node) ->
        {ok, Result} = rpc:call(?NAME(Node), paxoid, max_id, [?GROUP], 5000),
        node_debug("result of max_id: ~p~n", [Result]),
        {Node, Result}
    end, names()),

    ?PROPERTY_MODULE:command_conclusion(RunnerNode, [max_id]),

    Results.

%%%===================================================================
%%% Helper Functions
%%%===================================================================

-define(NODE_DEBUG, true).

%% Should we do node debugging?
node_debug(Line, Args) ->
    case ?NODE_DEBUG of
        true ->
            lager:info("~p: " ++ Line, [?MODULE] ++ Args);
        false ->
            ok
    end.

%% @private
loop() ->
    receive
        terminate ->
            ok
    end,
    loop().

%% @private
node_begin_property() ->
    partisan_trace_orchestrator:start_link().

%% @private
node_begin_case() ->
    %% Get nodes.
    [{nodes, Nodes}] = ets:lookup(prop_partisan, nodes),

    %% Enable pid encoding.
    lists:foreach(fun({ShortName, _}) ->
        node_debug("enabling pid_encoding at node ~p", [ShortName]),
        ok = rpc:call(?NAME(ShortName), partisan_config, set, [pid_encoding, true])
    end, Nodes),

    %% Enable register_pid_for_encoding.
    lists:foreach(fun({ShortName, _}) ->
        node_debug("enabling register_pid_for_encoding at node ~p", [ShortName]),
        ok = rpc:call(?NAME(ShortName), partisan_config, set, [register_pid_for_encoding, true])
    end, Nodes),

    %% Load, configure, and start paxoid.
    lists:foreach(fun({ShortName, _}) ->
        node_debug("starting paxoid at node ~p", [ShortName]),
        ok = rpc:call(?NAME(ShortName), application, load, [paxoid]),

        node_debug("configuring paxoid at node ~p", [ShortName]),
        ok = rpc:call(?NAME(ShortName), application, set_env, [paxoid, predefined, [paxoid]]),

        node_debug("starting paxoid at node ~p", [ShortName]),
        {ok, _} = rpc:call(?NAME(ShortName), application, ensure_all_started, [paxoid])
    end, Nodes),

    %% Join.
    OtherNodes = lists:map(fun({ShortName, _}) -> ?NAME(ShortName) end, tl(Nodes)),
    {FirstName, _} = hd(Nodes),
    node_debug("joining all nodes with paxoid to first node: ~p: ~p", [FirstName, OtherNodes]),
    ok = rpc:call(?NAME(FirstName), paxoid, join, [?GROUP, OtherNodes]),

    %% Info.
    node_debug("getting info from paxoid on first node", []),
    {ok, Info} = rpc:call(?NAME(FirstName), paxoid, info, [?GROUP]),
    node_debug("=> info: ~p", [Info]),

    %% Sleep.
    node_debug("sleeping for convergence", []),
    timer:sleep(1000),
    node_debug("done.", []),

    ok.

%% @private
node_end_case() ->
{'fraction_non_alphanumeric': 0.2422064056939502, 'fraction_numerical': 0.003487544483985765, 'mean_word_length': 3.683666666666667, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 87, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2860289', 'n_tokens_mistral': 4403, 'n_tokens_neox': 4198, 'n_words': 1036}