anchor.diff:      ])).
   
   
  +%% @private
  +create_setup_view_transfer_env(TransferType, SrcNode, DstNode, UserId, Config) ->
  +    fun() ->
  +        SessId1 = ?SESS_ID(UserId, SrcNode, Config),
  +        SessId2 = ?SESS_ID(UserId, DstNode, Config),
  +
  +        FilesToTransferNum = 3,
  +        RootDirPath = filename:join(["/", ?SPACE_2]),
  +        {ViewName, Xattr} = create_view(TransferType, SrcNode, DstNode),
  +
  +        FilesToTransfer = lists:map(fun(_) ->
  +            FileGuid = create_file(SrcNode, SessId1, RootDirPath),
  +            ?assertMatch(ok, lfm_proxy:set_xattr(SrcNode, SessId1, {guid, FileGuid}, Xattr)),
  +            FileGuid
  +        end, lists:seq(1, FilesToTransferNum)),
  +
  +        OtherFiles = [create_file(SrcNode, SessId1, RootDirPath)],
  +
  +        sync_files_between_nodes(
  +            TransferType, SrcNode, SessId1, DstNode, SessId2,
  +            OtherFiles ++ FilesToTransfer
  +        ),
  +
  +        ObjectIds = api_test_utils:guids_to_object_ids(FilesToTransfer),
  +        QueryViewParams = [{key, Xattr#xattr.value}],
  +
  +        case TransferType of
  +            replication ->
  +                % Wait until FilesToTransfer are all indexed by view on DstNode.
  +                % Otherwise some of them could be omitted from replication.
  +                ?assertViewQuery(ObjectIds, DstNode, ?SPACE_2, ViewName,  QueryViewParams);
  +            eviction ->
  +                % Wait until file_distribution containing entries for both nodes
  +                % and all FilesToTransfer are indexed by view on SrcNode.
  +                % Otherwise some of them could be omitted from eviction (if data
  +                % replicas don't exist on other providers it is skipped).
  +                assert_distribution(
  +                    SrcNode, SessId1, OtherFiles ++ FilesToTransfer,
  +                    [{SrcNode, ?BYTES_NUM}, {DstNode, ?BYTES_NUM}]
  +                ),
  +                ?assertViewQuery(ObjectIds, SrcNode, ?SPACE_2, ViewName,  QueryViewParams);
  +            migration ->
  +                % Wait until FilesToTransfer are all indexed by view on SrcNode and DstNode.
  +                % Otherwise some of them could be omitted from replication/eviction.
  +                ?assertViewQuery(ObjectIds, SrcNode, ?SPACE_2, ViewName,  QueryViewParams),
  +                ?assertViewQuery(ObjectIds, DstNode, ?SPACE_2, ViewName,  QueryViewParams)
  +        end,
  +        ExpTransfer = get_exp_transfer_stats(
  +            TransferType, <<"dir">>, SrcNode, DstNode, length(FilesToTransfer)
  +        ),
  +
  +        #{
  +            view_name => ViewName,
  +            exp_transfer => ExpTransfer#{
  +                space_id => ?SPACE_2,
  +                file_uuid => fslogic_uuid:spaceid_to_space_dir_uuid(?SPACE_2),
  +                path => RootDirPath,
  +                failed_files => 0
  +            },
  +            files_to_transfer => FilesToTransfer,
  +            other_files => OtherFiles
  +        }
  +    end.
  +
  +
   %%%===================================================================
   %%% Common transfer helper functions
   %%%===================================================================
  
positive.code:             #data_spec{bad_values = BadFileIdValues};
          #data_spec{bad_values = BadValues} ->
              DataSpec#data_spec{bad_values = BadFileIdValues ++ BadValues}
      end.
  
  
  %% @private
  create_setup_view_transfer_env(Type, SrcNode, DstNode, UserId, Config) ->
      fun() ->
          SessId1 = ?SESS_ID(UserId, SrcNode, Config),
          SessId2 = ?SESS_ID(UserId, DstNode, Config),
  
          {ViewName, Xattr} = create_view(Type, SrcNode, DstNode),
          RootDirPath = filename:join(["/", ?SPACE_2]),
  
          FilesToBeLeftAlone = lists:map(fun(_) ->
              create_file(SrcNode, SessId1, RootDirPath)
          end, lists:seq(1, 3)),
  
          FilesToTransferNum = 3,
          FilesToTransfer = lists:map(fun(_) ->
              FileGuid = create_file(SrcNode, SessId1, RootDirPath),
              ?assertMatch(ok, lfm_proxy:set_xattr(SrcNode, SessId1, {guid, FileGuid}, Xattr)),
              FileGuid
          end, lists:seq(1, FilesToTransferNum)),
  
          sync_files_between_nodes(Type, SrcNode, SessId1, DstNode, SessId2, FilesToTransfer),
  
          ObjectIds = api_test_utils:guids_to_object_ids(FilesToTransfer),
          QueryViewParams = [{key, Xattr#xattr.value}],
  
          ExpTransfer = case Type of
              replication ->
                  ?assertViewQuery(ObjectIds, DstNode, ?SPACE_2, ViewName,  QueryViewParams),
  
                  #{
                      replication_status => completed,
                      eviction_status => skipped,
                      replicating_provider => transfers_test_utils:provider_id(DstNode),
                      evicting_provider => undefined,
                      files_to_process => 1 + FilesToTransferNum,
                      files_processed => 1 + FilesToTransferNum,
                      files_replicated => FilesToTransferNum,
                      bytes_replicated => FilesToTransferNum * ?BYTES_NUM,
                      files_evicted => 0
                  };
              eviction ->
                  ?assertViewQuery(ObjectIds, SrcNode, ?SPACE_2, ViewName,  QueryViewParams),
                  timer:sleep(timer:seconds(5)),
  
                  #{
                      replication_status => skipped,
                      eviction_status => completed,
                      replicating_provider => undefined,
                      evicting_provider => transfers_test_utils:provider_id(SrcNode),
                      files_to_process => 1 + FilesToTransferNum,
                      files_processed => 1 + FilesToTransferNum,
                      files_replicated => 0,
                      bytes_replicated => 0,
                      files_evicted => FilesToTransferNum
                  };
              migration ->
                  ?assertViewQuery(ObjectIds, SrcNode, ?SPACE_2, ViewName,  QueryViewParams),
                  ?assertViewQuery(ObjectIds, DstNode, ?SPACE_2, ViewName,  QueryViewParams),
  
                  #{
                      replication_status => completed,
                      eviction_status => completed,
                      replicating_provider => transfers_test_utils:provider_id(DstNode),
                      evicting_provider => transfers_test_utils:provider_id(SrcNode),
                      files_to_process => 2 * (1 + FilesToTransferNum),
                      files_processed => 2 * (1 + FilesToTransferNum),
                      files_replicated => FilesToTransferNum,
                      bytes_replicated => FilesToTransferNum * ?BYTES_NUM,
                      files_evicted => FilesToTransferNum
                  }
          end,
  
          #{
              view_name => ViewName,
              exp_transfer => ExpTransfer#{
                  space_id => ?SPACE_2,
                  file_uuid => fslogic_uuid:spaceid_to_space_dir_uuid(?SPACE_2),
                  path => RootDirPath,
                  failed_files => 0
              },
              files_to_transfer => FilesToTransfer,
              other_files => FilesToBeLeftAlone
          }
      end.
  
  
  
negative.code: 
      fun
          (expected_failure, #api_test_ctx{env = #{files_to_transfer := FilesToTransfer, other_files := OtherFiles}}) ->
              assert_distribution(
                  Node, SessId, OtherFiles ++ FilesToTransfer,
                  [{SrcProvider, ?BYTES_NUM}, {DstProvider, ?BYTES_NUM}]
              ),
              true;
          (expected_success, #api_test_ctx{env = #{files_to_transfer := FilesToTransfer, other_files := OtherFiles}}) ->
              assert_distribution(
                  Node, SessId, OtherFiles,
                  [{SrcProvider, ?BYTES_NUM}, {DstProvider, ?BYTES_NUM}]
              ),
              assert_distribution(
                  Node, SessId, FilesToTransfer,
                  [{SrcProvider, 0}, {DstProvider, ?BYTES_NUM}]
  