anchor.diff:  %%%===================================================================
   
   open_failure_mock(Worker) ->
  -  % mock for open error - note that error is raised after
  -  % register_open is performed
  -  test_utils:mock_expect(Worker, storage_driver, open,
  -    fun(SDHandle2, Flag) ->
  -      meck:passthrough([SDHandle2, Flag]),
  -      throw(error)
  -    end).
  +    % mock for open error - note that error is raised after
  +    % register_open is performed
  +    test_utils:mock_expect(Worker, storage_driver, open,
  +        fun(SDHandle2, Flag) ->
  +            meck:passthrough([SDHandle2, Flag]),
  +            throw(error)
  +        end).
   
   print_mem_and_disc_docs_diff(Worker, MemEntriesBefore, CacheEntriesBefore,
       MemEntriesAfter, CacheEntriesAfter) ->
  -  MemDiff = pool_utils:get_documents_diff(Worker, MemEntriesAfter,
  -    MemEntriesBefore),
  -  CacheDiff = pool_utils:get_documents_diff(Worker, CacheEntriesAfter,
  -    CacheEntriesBefore),
  -  ct:pal("~n MemRes: ~p ~n~n CacheRes: ~p ~n", [MemDiff, CacheDiff]).
  +    MemDiff = pool_utils:get_documents_diff(Worker, MemEntriesAfter,
  +        MemEntriesBefore),
  +    CacheDiff = pool_utils:get_documents_diff(Worker, CacheEntriesAfter,
  +        CacheEntriesBefore),
  +    ct:pal("~n MemRes: ~p ~n~n CacheRes: ~p ~n", [MemDiff, CacheDiff]).
   
   get_mem_and_disc_entries(Worker) ->
  -  {MemEntries, _} = pool_utils:get_pools_entries_and_sizes(Worker, memory),
  -  {DiscEntries, _} = pool_utils:get_pools_entries_and_sizes(Worker, disc),
  -  {MemEntries, DiscEntries}.
  +    {MemEntries, _} = pool_utils:get_pools_entries_and_sizes(Worker, memory),
  +    {DiscEntries, _} = pool_utils:get_pools_entries_and_sizes(Worker, disc),
  +    {MemEntries, DiscEntries}.
   
   get_session_file_handles_num(W, FileGuid, SessionId) ->
  -  FileUuid = file_id:guid_to_uuid(FileGuid),
  -  {ok, [#document{key = FileUuid, value = FileHandlesRec} | _]} = rpc:call(
  -    W, file_handles, list, []
  -  ),
  -  Descriptors = FileHandlesRec#file_handles.descriptors,
  -  case maps:find(SessionId, Descriptors) of
  -    {ok, HandlesNum} ->
  -      HandlesNum;
  -    error ->
  -      0
  -  end.
  +    FileUuid = file_id:guid_to_uuid(FileGuid),
  +    {ok, [#document{key = FileUuid, value = FileHandlesRec} | _]} = rpc:call(
  +        W, file_handles, list, []
  +    ),
  +    Descriptors = FileHandlesRec#file_handles.descriptors,
  +    case maps:find(SessionId, Descriptors) of
  +        {ok, HandlesNum} ->
  +            HandlesNum;
  +        error ->
  +            0
  +    end.
   
   %% Get guid of given by path file. Possible as root to bypass permissions checks.
   get_guid_privileged(Worker, SessId, Path) ->
  -  get_guid(Worker, SessId, Path).
  +    get_guid(Worker, SessId, Path).
   
   get_guid(Worker, SessId, Path) ->
  -  #fuse_response{fuse_response = #guid{guid = Guid}} =
  -    ?assertMatch(
  -      #fuse_response{status = #status{code = ?OK}},
  -      ?req(Worker, SessId, #resolve_guid{path = Path}),
  -      30
  -    ),
  -  Guid.
  +    #fuse_response{fuse_response = #guid{guid = Guid}} =
  +        ?assertMatch(
  +            #fuse_response{status = #status{code = ?OK}},
  +            ?req(Worker, SessId, #resolve_guid{path = Path}),
  +            30
  +        ),
  +    Guid.
   
   for(From, To, Fun) ->
  -  for(From, To, 1, Fun).
  +    for(From, To, 1, Fun).
   for(From, To, Step, Fun) ->
  -  [Fun(I) || I <- lists:seq(From, To, Step)].
  +    [Fun(I) || I <- lists:seq(From, To, Step)].
   
   measure_execution_time(Fun) ->
  -  StartTime = os:timestamp(),
  -  Ans = Fun(),
  -  Now = os:timestamp(),
  -  {timer:now_diff(Now, StartTime), Ans}.
  +    StartTime = os:timestamp(),
  +    Ans = Fun(),
  +    Now = os:timestamp(),
  +    {timer:now_diff(Now, StartTime), Ans}.
   
   check_run_parallel_ans(0) ->
  -  ok;
  +    ok;
   check_run_parallel_ans(Num) ->
  -  RStatus = receive
  -              run_parallel_ok ->
  -                ok
  -            after
  -              100000 ->
  -                timeout
  -            end,
  -  ?assertEqual(ok, RStatus),
  -  check_run_parallel_ans(Num - 1).
  +    RStatus = receive
  +        run_parallel_ok ->
  +            ok
  +    after
  +        100000 ->
  +            timeout
  +    end,
  +    ?assertEqual(ok, RStatus),
  +    check_run_parallel_ans(Num - 1).
   
   report_success(Master) ->
  -  Master ! run_parallel_ok.
  +    Master ! run_parallel_ok.
   
   wait_for_cache_dump(Workers) ->
  -  lists:foreach(fun(W) ->
  -    rpc:call(W, caches_controller, wait_for_cache_dump, [])
  -                end, Workers).
  +    lists:foreach(fun(W) ->
  +        rpc:call(W, caches_controller, wait_for_cache_dump, [])
  +    end, Workers).
   
   generate_dir(Config, Size) ->
  -  [Worker | _] = ?config(op_worker_nodes, Config),
  -
  -  {SessId1, _UserId1} =
  -    {?config({session_id, {<<"user1">>, ?GET_DOMAIN(Worker)}}, Config), ?config({user_id, <<"user1">>}, Config)},
  -
  -  MainDir = generator:gen_name(),
  -  MainDirPath = <<"/space_name1/", MainDir/binary, "/">>,
  -  ?assertMatch({ok, _}, lfm_proxy:mkdir(Worker, SessId1, MainDirPath, 8#755)),
  -
  -  case Size of
  -    0 ->
  -      {MainDirPath, []};
  -    _ ->
  -      Files = lists:sort(lists:map(fun(_) ->
  -        generator:gen_name() end, lists:seq(1, Size))),
  -      lists:foreach(fun(F) ->
  -        ?assertMatch({ok, _}, lfm_proxy:create(Worker, SessId1, <<MainDirPath/binary, F/binary>>, 8#755))
  -                    end, Files),
  -
  -      {MainDirPath, Files}
  -  end.
  +    [Worker | _] = ?config(op_worker_nodes, Config),
  +
  +    {SessId1, _UserId1} =
  +        {?config({session_id, {<<"user1">>, ?GET_DOMAIN(Worker)}}, Config), ?config({user_id, <<"user1">>}, Config)},
  +
  +    MainDir = generator:gen_name(),
  +    MainDirPath = <<"/space_name1/", MainDir/binary, "/">>,
  +    ?assertMatch({ok, _}, lfm_proxy:mkdir(Worker, SessId1, MainDirPath, 8#755)),
  +
  +    case Size of
  +        0 ->
  +            {MainDirPath, []};
  +        _ ->
  +            Files = lists:sort(lists:map(fun(_) ->
  +                generator:gen_name() end, lists:seq(1, Size))),
  +            lists:foreach(fun(F) ->
  +                ?assertMatch({ok, _}, lfm_proxy:create(Worker, SessId1, <<MainDirPath/binary, F/binary>>, 8#755))
  +            end, Files),
  +
  +            {MainDirPath, Files}
  +    end.
   
   verify_attrs(Config, MainDirPath, Files, Limit, ExpectedSize) ->
  -  verify_attrs(Config, MainDirPath, Files, Limit, ExpectedSize, 0).
  +    verify_attrs(Config, MainDirPath, Files, Limit, ExpectedSize, 0).
   
   verify_attrs(Config, MainDirPath, Files, Limit, ExpectedSize, Offset) ->
  -  [Worker | _] = ?config(op_worker_nodes, Config),
  -
  -  {SessId1, _UserId1} =
  -    {?config({session_id, {<<"user1">>, ?GET_DOMAIN(Worker)}}, Config), ?config({user_id, <<"user1">>}, Config)},
  -
  -  Ans = lfm_proxy:read_dir_plus(Worker, SessId1, {path, MainDirPath}, Offset, Limit),
  -  ?assertMatch({ok, _}, Ans),
  -  {ok, List} = Ans,
  -  ?assertEqual(ExpectedSize, length(List)),
  -
  -  lists:foreach(fun({F1, F2}) ->
  -    ?assertEqual(F1#file_attr.name, F2)
  -                end, lists:zip(List, lists:sublist(Files, Offset + 1, ExpectedSize))).
  +    [Worker | _] = ?config(op_worker_nodes, Config),
  +
  +    {SessId1, _UserId1} =
  +        {?config({session_id, {<<"user1">>, ?GET_DOMAIN(Worker)}}, Config), ?config({user_id, <<"user1">>}, Config)},
  +
  +    Ans = lfm_proxy:read_dir_plus(Worker, SessId1, {path, MainDirPath}, Offset, Limit),
  +    ?assertMatch({ok, _}, Ans),
  +    {ok, List} = Ans,
  +    ?assertEqual(ExpectedSize, length(List)),
  +
  +    lists:foreach(fun({F1, F2}) ->
  +        ?assertEqual(F1#file_attr.name, F2)
  +    end, lists:zip(List, lists:sublist(Files, Offset + 1, ExpectedSize))).
   
   verify_attrs_with_token(Config, MainDirPath, Files, ExpectedSize, Limit, Offset, IsLast, Token) ->
  -  [Worker | _] = ?config(op_worker_nodes, Config),
  -
  -  {SessId1, _UserId1} =
  -    {?config({session_id, {<<"user1">>, ?GET_DOMAIN(Worker)}}, Config), ?config({user_id, <<"user1">>}, Config)},
  -
  -  Ans = lfm_proxy:read_dir_plus(Worker, SessId1, {path, MainDirPath}, 0, Limit, Token),
  -  ?assertMatch({ok, _, _, _}, Ans),
  -  {ok, List, Token2, IL} = Ans,
  -  ?assertEqual(ExpectedSize, length(List)),
  -
  -  lists:foreach(fun({F1, F2}) ->
  -    ?assertEqual(F1#file_attr.name, F2)
  -                end, lists:zip(List, lists:sublist(Files, Offset + 1, ExpectedSize))),
  -  ?assertEqual(IsLast, IL),
  -  Token2.
  +    [Worker | _] = ?config(op_worker_nodes, Config),
  +
  +    {SessId1, _UserId1} =
  +        {?config({session_id, {<<"user1">>, ?GET_DOMAIN(Worker)}}, Config), ?config({user_id, <<"user1">>}, Config)},
  +
  +    Ans = lfm_proxy:read_dir_plus(Worker, SessId1, {path, MainDirPath}, 0, Limit, Token),
  +    ?assertMatch({ok, _, _, _}, Ans),
  +    {ok, List, Token2, IL} = Ans,
  +    ?assertEqual(ExpectedSize, length(List)),
  +
  +    lists:foreach(fun({F1, F2}) ->
  +        ?assertEqual(F1#file_attr.name, F2)
  +    end, lists:zip(List, lists:sublist(Files, Offset + 1, ExpectedSize))),
  +    ?assertEqual(IsLast, IL),
  +    Token2.
   
   verify_with_token(Config, MainDirPath, Files, ExpectedSize, Limit, Offset, IsLast, Token) ->
  -  [Worker | _] = ?config(op_worker_nodes, Config),
  -
  -  {SessId1, _UserId1} =
  -    {?config({session_id, {<<"user1">>, ?GET_DOMAIN(Worker)}}, Config), ?config({user_id, <<"user1">>}, Config)},
  -
  -  Ans = lfm_proxy:ls(Worker, SessId1, {path, MainDirPath}, 0, Limit, Token),
  -  ?assertMatch({ok, _, _, _}, Ans),
  -  {ok, List, Token2, IL} = Ans,
  -  ?assertEqual(ExpectedSize, length(List)),
  -
  -  lists:foreach(fun({{_, F1}, F2}) ->
  -    ?assertEqual(F1, F2)
  -                end, lists:zip(List, lists:sublist(Files, Offset + 1, ExpectedSize))),
  -  ?assertEqual(IsLast, IL),
  -  Token2.
  +    [Worker | _] = ?config(op_worker_nodes, Config),
  +
  +    {SessId1, _UserId1} =
  +        {?config({session_id, {<<"user1">>, ?GET_DOMAIN(Worker)}}, Config), ?config({user_id, <<"user1">>}, Config)},
  +
  +    Ans = lfm_proxy:ls(Worker, SessId1, {path, MainDirPath}, 0, Limit, Token),
  +    ?assertMatch({ok, _, _, _}, Ans),
  +    {ok, List, Token2, IL} = Ans,
  +    ?assertEqual(ExpectedSize, length(List)),
  +
  +    lists:foreach(fun({{_, F1}, F2}) ->
  +        ?assertEqual(F1, F2)
  +    end, lists:zip(List, lists:sublist(Files, Offset + 1, ExpectedSize))),
  +    ?assertEqual(IsLast, IL),
  +    Token2.
   
   verify_with_startid(Config, MainDirPath, Files, FilesOffset, ExpectedSize, Offset, Limit, StartId) ->
  -  [Worker | _] = ?config(op_worker_nodes, Config),
  -
  -  {SessId1, _UserId1} =
  -    {?config({session_id, {<<"user1">>, ?GET_DOMAIN(Worker)}}, Config), ?config({user_id, <<"user1">>}, Config)},
  -
  -  Ans = lfm_proxy:ls(Worker, SessId1, {path, MainDirPath}, Offset, Limit, undefined, StartId),
  -  {ok, List, _, _} = ?assertMatch({ok, _, _, _}, Ans),
  -  ?assertEqual(ExpectedSize, length(List)),
  -
  -  lists:foreach(fun({{_, F1}, F2}) ->
  -    ?assertEqual(F1, F2)
  -  end, lists:zip(List, lists:sublist(Files, FilesOffset + 1, ExpectedSize))),
  -
  -  case List of
  -    [_ | _] ->
  -      {_, NextStartId} = lists:last(List),
  -      NextStartId;
  -    _ ->
  -      undefined
  -  end.
  +    [Worker | _] = ?config(op_worker_nodes, Config),
  +
  +    {SessId1, _UserId1} =
  +        {?config({session_id, {<<"user1">>, ?GET_DOMAIN(Worker)}}, Config), ?config({user_id, <<"user1">>}, Config)},
  +
  +    Ans = lfm_proxy:ls(Worker, SessId1, {path, MainDirPath}, Offset, Limit, undefined, StartId),
  +    {ok, List, _, _} = ?assertMatch({ok, _, _, _}, Ans),
  +    ?assertEqual(ExpectedSize, length(List)),
  +
  +    lists:foreach(fun({{_, F1}, F2}) ->
  +        ?assertEqual(F1, F2)
  +    end, lists:zip(List, lists:sublist(Files, FilesOffset + 1, ExpectedSize))),
  +
  +    case List of
  +        [_ | _] ->
  +            {_, NextStartId} = lists:last(List),
  +            NextStartId;
  +        _ ->
  +            undefined
  +    end.
   
   verify_file_content(Config, Handle, FileContent) ->
  -  [Worker | _] = ?config(op_worker_nodes, Config),
  -
  -  case ?config(storage_type, Config) of
  -    posix -> ?assertEqual({ok, FileContent},
  -      lfm_proxy:read(Worker, Handle, 0, 100));
  -    _ -> ?assertEqual({ok, FileContent},
  -      lfm_proxy:read(Worker, Handle, 0, size(FileContent)))
  -  end.
  +    [Worker | _] = ?config(op_worker_nodes, Config),
  +
  +    case ?config(storage_type, Config) of
  +        posix -> ?assertEqual({ok, FileContent},
  +            lfm_proxy:read(Worker, Handle, 0, 100));
  +        _ -> ?assertEqual({ok, FileContent},
  +            lfm_proxy:read(Worker, Handle, 0, size(FileContent)))
  +    end.
   
   verify_file_content(Config, Handle, FileContent, From, To) ->
  -  [Worker | _] = ?config(op_worker_nodes, Config),
  -  ?assertEqual({ok, FileContent}, lfm_proxy:read(Worker, Handle, From, To)).
  +    [Worker | _] = ?config(op_worker_nodes, Config),
  +    ?assertEqual({ok, FileContent}, lfm_proxy:read(Worker, Handle, From, To)).
  
positive.code: -define(SUCCESS_RATE, 100).
  
  -define(req(W, SessId, FuseRequest), element(2, rpc:call(W, worker_proxy, call,
    [fslogic_worker, {fuse_request, SessId, #fuse_request{fuse_request = FuseRequest}}]))).
  
  -define(file_req(W, SessId, ContextGuid, FileRequest), ?req(W, SessId,
    #file_request{context_guid = ContextGuid, file_request = FileRequest})).
  
  -define(lfm_req(W, Method, Args), rpc:call(W, file_manager, Method, Args, ?TIMEOUT)).
  
  -define(cdmi_id(Guid), begin
                           {ok, FileId} = file_id:guid_to_objectid(Guid),
                           FileId
                         end).
  
  %%%====================================================================
  %%% Test function
  %%%====================================================================
  
  lfm_rmdir(Config) ->
    [W | _] = ?config(op_worker_nodes, Config),
    {SessId1, _UserId1} = {?config({session_id, {<<"user1">>, ?GET_DOMAIN(W)}}, Config), ?config({user_id, <<"user1">>}, Config)},
    DirPath = <<"/space_name1/dir1">>,
    ?assertMatch({ok, _}, lfm_proxy:mkdir(W, SessId1, DirPath, 8#755)),
    ?assertMatch(ok, lfm_proxy:unlink(W, SessId1, {path, DirPath})).
  
  lfm_recreate_handle(Config, CreatePerms, DeleteAfterOpen) ->
    [W | _] = ?config(op_worker_nodes, Config),
    {SessId1, _UserId1} = {
      ?config({session_id, {<<"user1">>, ?GET_DOMAIN(W)}}, Config),
      ?config({user_id, <<"user1">>}, Config)
    },
    {ok, {FileGuid, Handle}} = lfm_proxy:create_and_open(W, SessId1, <<"/space_name1/test_read">>, CreatePerms),
    case DeleteAfterOpen of
      delete_after_open ->
        ?assertEqual(ok, lfm_proxy:unlink(W, SessId1, {guid, FileGuid})),
        ?assertEqual(ok, rpc:call(W, permissions_cache, invalidate, []));
      _ ->
        ok
    end,
  
    % remove handle before write to file so that handle has to be recreated
    Context = rpc:call(W, ets, lookup_element, [lfm_handles, Handle, 2]),
    HandleId = lfm_context:get_handle_id(Context),
    ?assertEqual({error, not_found}, rpc:call(W, session_handles, get, [SessId1, HandleId])),
  
    % try to write to file to confirm that handle has been recreated
    FileContent = <<"test_data">>,
    ?assertEqual({ok, 9}, lfm_proxy:write(W, Handle, 0, FileContent)),
    verify_file_content(Config, Handle, FileContent),
  
    ?assertEqual(ok, lfm_proxy:close(W, Handle)),
  
    ?assertEqual(false, rpc:call(
      W, file_handles, exists, [file_id:guid_to_uuid(FileGuid)])
    ).
  
  lfm_open_failure(Config) ->
    [W | _] = ?config(op_worker_nodes, Config),
    {MemEntriesBefore, CacheEntriesBefore} = get_mem_and_disc_entries(W),
    {SessId1, _UserId1} = {
      ?config({session_id, {<<"user1">>, ?GET_DOMAIN(W)}}, Config),
      ?config({user_id, <<"user1">>}, Config)
    },
    {ok, FileGuid} = lfm_proxy:create(W, SessId1, <<"/space_name1/test_read">>, 8#755),
  
    % simulate open error
    open_failure_mock(W),
  
    ?assertEqual({error, ?EAGAIN}, lfm_proxy:open(W, SessId1, {guid, FileGuid}, rdwr)),
    ?assertEqual(false, rpc:call(
      W, file_handles, exists, [file_id:guid_to_uuid(FileGuid)])
    ),
  
    {MemEntriesAfter, CacheEntriesAfter} = get_mem_and_disc_entries(W),
    print_mem_and_disc_docs_diff(W, MemEntriesBefore, CacheEntriesBefore,
      MemEntriesAfter, CacheEntriesAfter).
  
  lfm_create_and_open_failure(Config) ->
    [W | _] = ?config(op_worker_nodes, Config),
    {MemEntriesBefore, CacheEntriesBefore} = get_mem_and_disc_entries(W),
    {SessId1, _UserId1} = {
      ?config({session_id, {<<"user1">>, ?GET_DOMAIN(W)}}, Config),
      ?config({user_id, <<"user1">>}, Config)
    },
    ParentGuid = get_guid(W, SessId1, <<"/space_name1">>),
  
    % simulate open error
    open_failure_mock(W),
  
    ?assertEqual({error, ?EAGAIN}, lfm_proxy:create_and_open(
      W, SessId1, ParentGuid, <<"test_read">>, 8#755)
    ),
    ?assertEqual({error, ?ENOENT}, lfm_proxy:stat(
      W, SessId1, {path, <<"/space_name1/test_read">>})
    ),
    ?assertEqual({ok, []}, rpc:call(W, file_handles, list, [])),
    {MemEntriesAfter, CacheEntriesAfter} = get_mem_and_disc_entries(W),
    print_mem_and_disc_docs_diff(W, MemEntriesBefore, MemEntriesAfter,
      CacheEntriesBefore, CacheEntriesAfter).
  
  lfm_open_and_create_open_failure(Config) ->
    [W | _] = ?config(op_worker_nodes, Config),
    {MemEntriesBefore, CacheEntriesBefore} = get_mem_and_disc_entries(W),
    {SessId1, _UserId1} = {
      ?config({session_id, {<<"user1">>, ?GET_DOMAIN(W)}}, Config),
      ?config({user_id, <<"user1">>}, Config)
    },
    ParentGuid = get_guid(W, SessId1, <<"/space_name1">>),
  
    % simulate open error
    open_failure_mock(W),
  
    ?assertEqual({error, ?EAGAIN}, lfm_proxy:create_and_open(
      W, SessId1, ParentGuid, <<"test_read">>, 8#755)
    ),
    ?assertEqual({error, ?ENOENT}, lfm_proxy:stat(
      W, SessId1, {path, <<"/space_name1/test_read">>})
    ),
    ?assertEqual({ok, []}, rpc:call(W, file_handles, list, [])),
  
    {ok, FileGuid} = lfm_proxy:create(W, SessId1, <<"/space_name1/test_read">>, 8#755),
    ?assertEqual({error, ?EAGAIN}, lfm_proxy:open(W, SessId1, {guid, FileGuid}, rdwr)),
    ?assertEqual(false, rpc:call(
      W, file_handles, exists, [file_id:guid_to_uuid(FileGuid)])
    ),
    {MemEntriesAfter, CacheEntriesAfter} = get_mem_and_disc_entries(W),
    print_mem_and_disc_docs_diff(W, MemEntriesBefore, MemEntriesAfter,
      CacheEntriesBefore, CacheEntriesAfter).
  
  lfm_open_multiple_times_failure(Config) ->
    [W | _] = ?config(op_worker_nodes, Config),
    {MemEntriesBefore, CacheEntriesBefore} = get_mem_and_disc_entries(W),
    {SessId1, _UserId1} = {
      ?config({session_id, {<<"user1">>, ?GET_DOMAIN(W)}}, Config),
      ?config({user_id, <<"user1">>}, Config)
    },
    {ok, FileGuid} = lfm_proxy:create(W, SessId1, <<"/space_name1/test_read">>, 8#755),
  
    % here all operations should succeed
    {ok, Handle} = lfm_proxy:open(W, SessId1, {guid, FileGuid}, rdwr),
    ?assertEqual({ok, 9}, lfm_proxy:write(W, Handle, 0, <<"test_data">>)),
    ?assertEqual(ok, lfm_proxy:close(W, Handle)),
  
    % simulate open error
    open_failure_mock(W),
  
    ?assertEqual({error, ?EAGAIN}, lfm_proxy:open(
      W, SessId1, {guid, FileGuid}, rdwr)
    ),
    ?assertEqual(false, rpc:call(
      W, file_handles, exists, [file_id:guid_to_uuid(FileGuid)])
    ),
  
    % unload mock for open so that it will succeed again
    test_utils:mock_unload(W, storage_driver),
  
    {ok, Handle2} = lfm_proxy:open(W, SessId1, {guid, FileGuid}, rdwr),
    ?assertEqual({ok, 11}, lfm_proxy:write(W, Handle2, 9, <<" test_data2">>)),
    verify_file_content(Config, Handle2, <<"test_data test_data2">>),
    ?assertEqual(ok, lfm_proxy:close(W, Handle2)),
  
    ?assertEqual(false, rpc:call(
      W, file_handles, exists, [file_id:guid_to_uuid(FileGuid)])
    ),
    {MemEntriesAfter, CacheEntriesAfter} = get_mem_and_disc_entries(W),
    print_mem_and_disc_docs_diff(W, MemEntriesBefore, MemEntriesAfter,
      CacheEntriesBefore, CacheEntriesAfter).
  
  lfm_open_failure_multiple_users(Config) ->
    [W | _] = ?config(op_worker_nodes, Config),
    {MemEntriesBefore, CacheEntriesBefore} = get_mem_and_disc_entries(W),
    {SessId1, _UserId1} = {
      ?config({session_id, {<<"user1">>, ?GET_DOMAIN(W)}}, Config),
      ?config({user_id, <<"user1">>}, Config)
    },
    {SessId2, _UserId2} = {
      ?config({session_id, {<<"user2">>, ?GET_DOMAIN(W)}}, Config),
      ?config({user_id, <<"user2">>}, Config)
    },
    {ok, FileGuid} = lfm_proxy:create(W, SessId1, <<"/space_name2/test_read">>, 8#775),
  
    % here all operations should succeed
    {ok, Handle} = lfm_proxy:open(W, SessId1, {guid, FileGuid}, rdwr),
    ?assertEqual({ok, 9}, lfm_proxy:write(W, Handle, 0, <<"test_data">>)),
  
    % simulate open error
    open_failure_mock(W),
  
    ?assertEqual({error, ?EAGAIN}, lfm_proxy:open(
      W, SessId2, {path, <<"/space_name2/test_read">>}, rdwr)
    ),
    ?assertEqual(0, get_session_file_handles_num(W, FileGuid, SessId2)),
  
    % check that user1 handle still exists
    ?assertEqual(1, get_session_file_handles_num(W, FileGuid, SessId1)),
  
    % unload mock for open so that operations will succeed again
    test_utils:mock_unload(W, storage_driver),
  
    % check that user1 can still use his handle
    ?assertEqual({ok, 11}, lfm_proxy:write(W, Handle, 9, <<" test_data2">>)),
    verify_file_content(Config, Handle, <<"test_data test_data2">>),
    ?assertEqual(ok, lfm_proxy:close(W, Handle)),
  
    ?assertEqual(false, rpc:call(
      W, file_handles, exists, [file_id:guid_to_uuid(FileGuid)])
    ),
    {MemEntriesAfter, CacheEntriesAfter} = get_mem_and_disc_entries(W),
    print_mem_and_disc_docs_diff(W, MemEntriesBefore, MemEntriesAfter,
      CacheEntriesBefore, CacheEntriesAfter).
  
  lfm_open_in_direct_mode(Config) ->
    [W | _] = ?config(op_worker_nodes, Config),
    {MemEntriesBefore, CacheEntriesBefore} = get_mem_and_disc_entries(W),
    {SessId1, _UserId1} = {
      ?config({session_id, {<<"user1">>, ?GET_DOMAIN(W)}}, Config),
      ?config({user_id, <<"user1">>}, Config)
    },
    {ok, FileGuid} = lfm_proxy:create(W, SessId1, <<"/space_name1/test_read">>, 8#755),
  
    {ok, Handle} = ?assertMatch({ok, _}, lfm_proxy:open(W, SessId1, {guid, FileGuid}, rdwr)),
  
    Context = rpc:call(W, ets, lookup_element, [lfm_handles, Handle, 2]),
    HandleId = lfm_context:get_handle_id(Context),
    ?assertEqual({error, not_found}, rpc:call(
      W, session_handles, get, [SessId1, HandleId])
    ),
    ?assertEqual(1, get_session_file_handles_num(W, FileGuid, SessId1)),
  
    {MemEntriesAfter, CacheEntriesAfter} = get_mem_and_disc_entries(W),
    print_mem_and_disc_docs_diff(W, MemEntriesBefore, MemEntriesAfter,
      CacheEntriesBefore, CacheEntriesAfter).
  
  lfm_copy_failure(Config) ->
    [W | _] = ?config(op_worker_nodes, Config),
    {MemEntriesBefore, CacheEntriesBefore} = get_mem_and_disc_entries(W),
    {SessId1, _UserId1} = {
      ?config({session_id, {<<"user1">>, ?GET_DOMAIN(W)}}, Config),
      ?config({user_id, <<"user1">>}, Config)
    },
    {ok, FileGuid} = lfm_proxy:create(W, SessId1, <<"/space_name1/test_read">>, 8#755),
  
    % simulate open error so that mv function will fail
    open_failure_mock(W),
  
    % file has to be moved to different space in order to use copy / delete
    ?assertEqual({error, ?EAGAIN}, lfm_proxy:mv(
      W, SessId1, {guid, FileGuid}, <<"/space_name2/test_read2">>)
    ),
    ?assertEqual({ok, []}, rpc:call(W, file_handles, list, [])),
    {MemEntriesAfter, CacheEntriesAfter} = get_mem_and_disc_entries(W),
    print_mem_and_disc_docs_diff(W, MemEntriesBefore, MemEntriesAfter,
      CacheEntriesBefore, CacheEntriesAfter).
  
  lfm_copy_failure_multiple_users(Config) ->
    [W | _] = ?config(op_worker_nodes, Config),
    {MemEntriesBefore, CacheEntriesBefore} = get_mem_and_disc_entries(W),
    {SessId1, _UserId1} = {
      ?config({session_id, {<<"user1">>, ?GET_DOMAIN(W)}}, Config),
      ?config({user_id, <<"user1">>}, Config)
    },
    {SessId2, _UserId2} = {
      ?config({session_id, {<<"user2">>, ?GET_DOMAIN(W)}}, Config),
      ?config({user_id, <<"user2">>}, Config)
    },
    {ok, FileGuid} = lfm_proxy:create(W, SessId1, <<"/space_name2/test_read">>, 8#775),
  
    % user1 succeeds to write to file using handle
    {ok, Handle} = lfm_proxy:open(W, SessId1, {guid, FileGuid}, rdwr),
    ?assertEqual({ok, 9}, lfm_proxy:write(W, Handle, 0, <<"test_data">>)),
  
    % simulate open error so that mv function will fail
    open_failure_mock(W),
  
    % user2 fails to move file
    ?assertEqual({error, ?EAGAIN}, lfm_proxy:mv(
      W, SessId2, {guid, FileGuid}, <<"/space_name3/test_read2">>)
    ),
    ?assertEqual(0, get_session_file_handles_num(W, FileGuid, SessId2)),
    {ok, Docs} = rpc:call(W, file_handles, list, []),
    ?assertEqual(1, length(Docs)),
  
    % unload mock for open so that operations will succeed again
    test_utils:mock_unload(W, storage_driver),
  
    % user1 handle should still exists
    ?assertEqual(1, get_session_file_handles_num(W, FileGuid, SessId1)),
  
    % check that user1 can still write to file using his handle
    ?assertEqual({ok, 11}, lfm_proxy:write(W, Handle, 9, <<" test_data2">>)),
    verify_file_content(Config, Handle, <<"test_data test_data2">>),
    ?assertEqual(ok, lfm_proxy:close(W, Handle)),
  
    ?assertEqual(false, rpc:call(
      W, file_handles, exists, [file_id:guid_to_uuid(FileGuid)])
    ),
    {MemEntriesAfter, CacheEntriesAfter} = get_mem_and_disc_entries(W),
    print_mem_and_disc_docs_diff(W, MemEntriesBefore, MemEntriesAfter,
      CacheEntriesBefore, CacheEntriesAfter).
  
  readdir_plus_should_return_empty_result_for_empty_dir(Config) ->
    {MainDirPath, Files} = generate_dir(Config, 0),
    verify_attrs(Config, MainDirPath, Files, 10, 0).
  
  readdir_plus_should_return_empty_result_zero_size(Config) ->
    {MainDirPath, Files} = generate_dir(Config, 10),
    verify_attrs(Config, MainDirPath, Files, 0, 0).
  
  readdir_plus_should_work_with_zero_offset(Config) ->
    {MainDirPath, Files} = generate_dir(Config, 5),
    verify_attrs(Config, MainDirPath, Files, 5, 5).
  
  readdir_plus_should_work_with_non_zero_offset(Config) ->
    {MainDirPath, Files} = generate_dir(Config, 5),
    verify_attrs(Config, MainDirPath, Files, 3, 3, 2).
  
  readdir_plus_should_work_with_size_greater_than_dir_size(Config) ->
    {MainDirPath, Files} = generate_dir(Config, 5),
    verify_attrs(Config, MainDirPath, Files, 10, 5).
  
  readdir_plus_should_work_with_token(Config) ->
    {MainDirPath, Files} = generate_dir(Config, 10),
    Token = verify_attrs_with_token(Config, MainDirPath, Files, 3, 3, 0, false, <<"">>),
    Token2 = verify_attrs_with_token(Config, MainDirPath, Files, 3, 3, 3, false, Token),
    Token3 = verify_attrs_with_token(Config, MainDirPath, Files, 3, 3, 6, false, Token2),
    Token4 = verify_attrs_with_token(Config, MainDirPath, Files, 1, 3, 9, true, Token3),
    ?assertEqual(<<"">>, Token4).
  
  readdir_plus_should_work_with_token2(Config) ->
    {MainDirPath, Files} = generate_dir(Config, 12),
    Token = verify_attrs_with_token(Config, MainDirPath, Files, 3, 3, 0, false, <<"">>),
    Token2 = verify_attrs_with_token(Config, MainDirPath, Files, 3, 3, 3, false, Token),
    Token3 = verify_attrs_with_token(Config, MainDirPath, Files, 3, 3, 6, false, Token2),
    Token4 = verify_attrs_with_token(Config, MainDirPath, Files, 3, 3, 9, true, Token3),
    ?assertEqual(<<"">>, Token4).
  
  readdir_should_work_with_token(Config) ->
    {MainDirPath, Files} = generate_dir(Config, 10),
    Token = verify_with_token(Config, MainDirPath, Files, 3, 3, 0, false, <<"">>),
    Token2 = verify_with_token(Config, MainDirPath, Files, 3, 3, 3, false, Token),
    Token3 = verify_with_token(Config, MainDirPath, Files, 3, 3, 6, false, Token2),
    Token4 = verify_with_token(Config, MainDirPath, Files, 1, 3, 9, true, Token3),
    ?assertEqual(<<"">>, Token4).
  
  readdir_should_work_with_token2(Config) ->
    {MainDirPath, Files} = generate_dir(Config, 12),
    Token = verify_with_token(Config, MainDirPath, Files, 3, 3, 0, false, <<"">>),
    Token2 = verify_with_token(Config, MainDirPath, Files, 3, 3, 3, false, Token),
    Token3 = verify_with_token(Config, MainDirPath, Files, 3, 3, 6, false, Token2),
    Token4 = verify_with_token(Config, MainDirPath, Files, 3, 3, 9, true, Token3),
    ?assertEqual(<<"">>, Token4).
  
  readdir_should_work_with_startid(Config) ->
    {MainDirPath, Files} = generate_dir(Config, 10),
  
    % list all files in chunks (use 0 offset for each chunk)
    StartId1 = verify_with_startid(Config, MainDirPath, Files, 0, 4, 0, 4, undefined),
    StartId2 = verify_with_startid(Config, MainDirPath, Files, 3, 4, 0, 4, StartId1),
    StartId3 = verify_with_startid(Config, MainDirPath, Files, 6, 3, 0, 3, StartId2),
    StartId4 = verify_with_startid(Config, MainDirPath, Files, 8, 2, 0, 3, StartId3),
    ?assertEqual(lists:last(Files), StartId4),
  
    % test ls with startid and positive offset
    StartId5 = verify_with_startid(Config, MainDirPath, Files, 4, 2, 4, 2, undefined),
    StartId6 = verify_with_startid(Config, MainDirPath, Files, 7, 3, 2, 4, StartId5),
    ?assertEqual(lists:last(Files), StartId6),
  
    % test ls with startid and offset beyond files num
    verify_with_startid(Config, MainDirPath, Files, 0, 0, 20, 4, StartId5),
  
    % test ls with startid and negative offset
    StartId7 = verify_with_startid(Config, MainDirPath, Files, 3, 4, -2, 4, StartId5),
    verify_with_startid(Config, MainDirPath, Files, 0, 6, -10, 6, StartId7).
  
  echo_loop(Config) ->
    ?PERFORMANCE(Config, [
      {repeats, ?REPEATS},
      {success_rate, ?SUCCESS_RATE},
      {parameters, [
        [{name, writes_num}, {value, 1000}, {description, "Number of write operations during "}]
      ]},
      {description, "Simulates loop of echo operations done by client"},
      {config, [{name, performance},
        {parameters, [
          [{name, writes_num}, {value, 10000}]
        ]},
        {description, "Basic performance configuration"}
      ]}
    ]).
  echo_loop_base(Config) ->
    WritesNum = ?config(writes_num, Config),
  
    [Worker | _] = Workers = ?config(op_worker_nodes, Config),
    wait_for_cache_dump(Workers),
  
    {SessId1, _UserId1} =
      {?config({session_id, {<<"user1">>, ?GET_DOMAIN(Worker)}}, Config), ?config({user_id, <<"user1">>}, Config)},
  
    File = generator:gen_name(),
    FilePath = <<"/space_name1/", File/binary, "/">>,
    ?assertMatch({ok, _}, lfm_proxy:create(Worker, SessId1, FilePath, 8#755)),
  
    {WriteTime, _} = measure_execution_time(fun() ->
      lists:foldl(fun(N, Offset) ->
        {ok, Handle} = ?assertMatch({ok, _},
          lfm_proxy:open(Worker, SessId1, {path, FilePath}, write)),
        Bytes = integer_to_binary(N),
        BufSize = size(Bytes),
        ?assertMatch({ok, BufSize}, lfm_proxy:write(Worker, Handle, Offset, Bytes)),
        lfm_proxy:close(Worker, Handle),
        Offset + BufSize
                  end, 0, lists:seq(1, WritesNum))
                                            end),
  
    #parameter{name = echo_time, value = WriteTime, unit = "us",
      description = "Aggregated time of all operations"}.
  
  ls_with_stats(Config) ->
    ?PERFORMANCE(Config, [
      {repeats, ?REPEATS},
      {success_rate, ?SUCCESS_RATE},
      {parameters, [
        [{name, proc_num}, {value, 1}, {description, "Number of threads used during the test."}],
        [{name, dir_level}, {value, 10}, {description, "Level of test directory."}],
        [{name, dirs_num_per_proc}, {value, 10}, {description, "Number of dirs tested by single thread."}]
      ]},
      {description, "Tests performance of ls with gettin stats operation"},
      {config, [{name, low_level_single_thread_small_dir},
        {parameters, [
          [{name, dir_level}, {value, 1}],
          [{name, dirs_num_per_proc}, {value, 5}]
        ]},
        {description, ""}
      ]},
      {config, [{name, low_level_single_thread_large_dir},
        {parameters, [
          [{name, dir_level}, {value, 1}],
          [{name, dirs_num_per_proc}, {value, 100}]
        ]},
        {description, ""}
      ]},
      {config, [{name, low_level_10_threads_large_dir},
        {parameters, [
          [{name, proc_num}, {value, 10}],
          [{name, dir_level}, {value, 1}],
          [{name, dirs_num_per_proc}, {value, 10}]
        ]},
        {description, ""}
      ]},
  %%        {config, [{name, low_level_many_threads_large_dir},
  %%            {parameters, [
  %%                [{name, proc_num}, {value, 100}],
  
negative.code: %%            ]},
  %%            {description, ""}
  %%        ]},
          {config, [{name, high_level_single_thread_small_dir},
              {parameters, [
                  [{name, dir_level}, {value, 100}],
                  [{name, dirs_num_per_proc}, {value, 5}]
              ]},
              {description, ""}
          ]},
          {config, [{name, high_level_single_thread_large_dir},
              {parameters, [
                  [{name, dir_level}, {value, 100}],
                  [{name, dirs_num_per_proc}, {value, 100}]
              ]},
              {description, ""}
          ]},
          {config, [{name, high_level_10_threads_large_dir},
              {parameters, [
                  [{name, proc_num}, {value, 10}],
                  [{name, dir_level}, {value, 100}],
                  [{name, dirs_num_per_proc}, {value, 10}]
              ]},
              {description, ""}
          ]}
  %%        {config, [{name, high_level_many_threads_large_dir},
  %%            {parameters, [
  %%                [{name, proc_num}, {value, 100}],
  