anchor.diff:      % in such case, provider should fall back to using domain for connections
       ?assertEqual({ok, [Domain1Bin]}, rpc:call(hd(Nodes2), provider_logic, get_nodes, [P1])),
       ?assertEqual({ok, [Domain2Bin]}, rpc:call(hd(Nodes1), provider_logic, get_nodes, [P2])).
  +
  +
  +% Providers should not connect because in env_up_posthook op version
  +% is mocked to be incompatible with current one
  +incompatible_providers_should_not_connect(Config) ->
  +    % providers should start connecting right after init_per_testcase
  +    % (spaces creation); just in case wait some time before checking
  +    % that connection failed
  +    timer:sleep(timer:seconds(30)),
  +
  +    % There are 2 providers and 3 nodes:
  +    %   * P1 -> 1 node
  +    %   * P2 -> 2 nodes
  +    Nodes = ?config(op_worker_nodes, Config),
  +    [Domain1, Domain2] = lists:usort([?GET_DOMAIN(N) || N <- Nodes]),
  +    Nodes1 = [N || N <- Nodes, ?GET_DOMAIN(N) =:= Domain1],
  +    Nodes2 = [N || N <- Nodes, ?GET_DOMAIN(N) =:= Domain2],
  +    P1 = hd(Nodes1),
  +    P2 = hd(Nodes2),
  +
  +    ?assertMatch(false, connection_exists(P1, P2)),
  +    ?assertMatch(false, connection_exists(P2, P1)),
  +
  +    test_utils:mock_unload(Nodes, op_worker),
  +    ?assertMatch(true, connection_exists(P1, P2), ?ATTEMPTS),
  +    ?assertMatch(true, connection_exists(P2, P1), ?ATTEMPTS),
  +
  +    ok.
  +
  +
  +provider_should_reconnect_after_loss_of_connection(Config) ->
  +    % There are 2 providers and 3 nodes:
  +    %   * P1 -> 1 node
  +    %   * P2 -> 2 nodes
  +    Nodes = ?config(op_worker_nodes, Config),
  +    [Domain1, Domain2] = lists:usort([?GET_DOMAIN(N) || N <- Nodes]),
  +    P1Worker = hd([N || N <- Nodes, ?GET_DOMAIN(N) =:= Domain1]),
  +    P2 = initializer:domain_to_provider_id(Domain2),
  +    OutgoingSessId = get_provider_session_id(P1Worker, outgoing, P2),
  +
  +    % undo initializer mock for get_nodes and reset connections
  +    GetNodesFun = fun(PID) ->
  +        {ok, IPsAtoms} = inet:getaddrs(binary_to_list(PID), inet),
  +        {ok, [list_to_binary(inet:ntoa(IP)) || IP <- IPsAtoms]}
  +    end,
  +    test_utils:mock_expect(Nodes, provider_logic, get_nodes, GetNodesFun),
  +    {ok, Cons} = list_session_connections(P1Worker, OutgoingSessId),
  +    lists:foreach(fun(Conn) -> connection:close(Conn) end, Cons),
  +
  +    {ok, [Conn2, Conn1]} = ?assertMatch(
  +        {ok, [_, _]},
  +        list_session_connections(P1Worker, OutgoingSessId),
  +        ?ATTEMPTS
  +    ),
  +    connection:close(Conn1),
  +    {ok, [Conn3, _]} = ?assertMatch(
  +        {ok, [_Conn3, Conn2]},
  +        list_session_connections(P1Worker, OutgoingSessId),
  +        ?ATTEMPTS
  +    ),
  +
  +    ?assertNotEqual(Conn1, Conn3).
  +
  +
  +after_connection_timeout_session_is_terminated(Config) ->
  +    % There are 2 providers and 3 nodes:
  +    %   * P1 -> 1 node
  +    %   * P2 -> 2 nodes
  +    Nodes = ?config(op_worker_nodes, Config),
  +    test_utils:mock_new(Nodes, session_connections),
  +    test_utils:mock_expect(Nodes, session_connections, ensure_connected, fun(_) -> ok end),
  +
  +    [Domain1, Domain2] = lists:usort([?GET_DOMAIN(N) || N <- Nodes]),
  +    P1 = hd([N || N <- Nodes, ?GET_DOMAIN(N) =:= Domain1]),
  +    P2Id = initializer:domain_to_provider_id(Domain2),
  +    OutgoingSessId = get_provider_session_id(P1, outgoing, P2Id),
  +
  +    % when one of session connection timeouts
  +    {ok, [Conn2, Conn1]} = ?assertMatch(
  +        {ok, [_, _]},
  +        list_session_connections(P1, OutgoingSessId),
  +        ?ATTEMPTS
  +    ),
  +    ConnManager = get_outgoing_connection_manager(P1, OutgoingSessId),
  +
  +    ?assertMatch(true, rpc:call(P1, erlang, is_process_alive, [Conn1])),
  +    ?assertMatch(true, rpc:call(P1, erlang, is_process_alive, [Conn2])),
  +    ?assertMatch(true, rpc:call(P1, erlang, is_process_alive, [ConnManager])),
  +
  +    Conn1 ! timeout,
  +
  +    % then entire session and it's connections should be terminated
  +    ?assertMatch(false, session_exists(P1, OutgoingSessId), ?ATTEMPTS),
  +    ?assertMatch(false, rpc:call(P1, erlang, is_process_alive, [Conn1])),
  +    ?assertMatch(false, rpc:call(P1, erlang, is_process_alive, [Conn2])),
  +    ?assertMatch(false, rpc:call(P1, erlang, is_process_alive, [ConnManager])),
  +    ?assertMatch({error, not_found}, list_session_connections(P1, OutgoingSessId), ?ATTEMPTS),
  +
  +    test_utils:mock_unload(Nodes, [session_connections]).
   
   
   configuration_endpoint_is_served(Config) ->
  
positive.code: ]).
  
  -export([
      incompatible_providers_should_not_connect/1,
      provider_should_reconnect_after_loss_of_connection/1,
      after_connection_timeout_session_is_terminated/1,
      provider_logic_correctly_resolves_nodes_to_connect/1,
      configuration_endpoint_is_served/1,
      deprecated_configuration_endpoint_is_served/1,
      broken_compatibility_file_causes_unknown_entries_in_configuration/1
  
negative.code: -spec node_ip(node()) -> inet:ip4_address().
  node_ip(Node) ->
      {ok, [IP]} = inet:getaddrs(?GET_HOSTNAME(Node), inet),
      IP.