anchor.diff:          get_shared_file_json_metadata_without_json_set_test,
           get_shared_dir_json_metadata_without_json_set_test,
           get_file_json_metadata_on_provider_not_supporting_space_test,
  -        get_dir_json_metadata_on_provider_not_supporting_space_test
  -
  -
  -%%        get_xattr_metadata_test,
  +        get_dir_json_metadata_on_provider_not_supporting_space_test,
  +
  +        get_file_xattrs_with_json_set_test,
  +        get_dir_xattrs_with_json_set_test,
  +        get_file_xattrs_without_json_set_test,
  +        get_dir_xattrs_without_json_set_test,
  +        get_shared_file_xattrs_with_json_set_test,
  +        get_shared_dir_xattrs_with_json_set_test,
  +        get_shared_file_xattrs_without_json_set_test,
  +        get_shared_dir_xattrs_without_json_set_test,
  +        get_file_xattrs_on_provider_not_supporting_space_test,
  +        get_dir_xattrs_on_provider_not_supporting_space_test
  +
  +
   %%        set_rdf_metadata_test,
   %%        set_json_metadata_test
       ]).
  
positive.code: 
  
  %%%===================================================================
  %%% Get metadata generic functions
  %%%===================================================================
  
  
  %% @private
  create_validate_get_metadata_rest_call_fun(GetExpResultFun) ->
      create_validate_get_metadata_rest_call_fun(GetExpResultFun, undefined).
  
  
  %% @private
  create_validate_get_metadata_rest_call_fun(GetExpResultFun, ProviderNotSupportingSpace) ->
      fun
          (#api_test_ctx{node = TestNode}, {ok, RespCode, RespBody}) when TestNode == ProviderNotSupportingSpace ->
              ProviderDomain = ?GET_DOMAIN_BIN(ProviderNotSupportingSpace),
              ExpError = ?REST_ERROR(?ERROR_SPACE_NOT_SUPPORTED_BY(ProviderDomain)),
              ?assertEqual({?HTTP_400_BAD_REQUEST, ExpError}, {RespCode, RespBody});
          (TestCtx, {ok, RespCode, RespBody}) ->
              case GetExpResultFun(TestCtx) of
                  {ok, ExpMetadata} ->
                      ?assertEqual({?HTTP_200_OK, ExpMetadata}, {RespCode, RespBody});
                  {error, _} = Error ->
                      ExpRestError = {errors:to_http_code(Error), ?REST_ERROR(Error)},
                      ?assertEqual(ExpRestError, {RespCode, RespBody})
              end
      end.
  
  
  %% @private
  create_validate_get_metadata_gs_call_fun(GetExpResultFun) ->
      create_validate_get_metadata_gs_call_fun(GetExpResultFun, undefined).
  
  
  %% @private
  create_validate_get_metadata_gs_call_fun(GetExpResultFun, ProviderNotSupportingSpace) ->
      fun
          (#api_test_ctx{node = TestNode}, Result) when TestNode == ProviderNotSupportingSpace ->
              ProviderDomain = ?GET_DOMAIN_BIN(ProviderNotSupportingSpace),
              ExpError = ?ERROR_SPACE_NOT_SUPPORTED_BY(ProviderDomain),
              ?assertEqual(ExpError, Result);
          (TestCtx, Result) ->
              case GetExpResultFun(TestCtx) of
                  {ok, ExpMetadata} ->
                      ?assertEqual({ok, #{<<"metadata">> => ExpMetadata}}, Result);
                  {error, _} = ExpError ->
                      ?assertEqual(ExpError, Result)
              end
      end.
  
  
  %% @private
  -spec get_metadata_test_base(
      MetadataType :: binary(),  %% <<"json">> | <<"rdf">> | <<"xattrs">>
      FileType :: binary(),      %% <<"dir">> | <<"file">>
      FilePath :: file_meta:path(),
      FileGuid :: file_id:file_guid(),
      ShareId :: undefined | od_share:id(),
      ValidateRestCallResultFun :: fun((api_test_ctx(), {ok, RespCode :: pos_integer(), RespBody :: term()}) -> ok),
      ValidateGsCallResultFun :: fun((api_test_ctx(), Result :: term()) -> ok),
      Providers :: [node()],
      client_spec(),
      data_spec(),
      QsParameters :: [binary()],
      Config :: proplists:proplist()
  ) ->
      ok.
  get_metadata_test_base(
      MetadataType, FileType, FilePath, FileGuid, _ShareId = undefined,
      ValidateRestCallResultFun, ValidateGsCallResultFun,
      Providers, ClientSpec, DataSpec, QsParameters, Config
  ) ->
      {ok, FileObjectId} = file_id:guid_to_objectid(FileGuid),
  
      ?assert(api_test_utils:run_scenarios(Config, [
          #scenario_spec{
              name = <<"Get ", MetadataType/binary, " metadata from ", FileType/binary, " using rest endpoint">>,
              type = rest,
              target_nodes = Providers,
              client_spec = ClientSpec,
              prepare_args_fun = ?GET_METADATA_REST_ARGS_FUN(MetadataType, FileObjectId, QsParameters),
              validate_result_fun = ValidateRestCallResultFun,
              data_spec = DataSpec
          },
          #scenario_spec{
              name = <<"Get ", MetadataType/binary, " metadata from ", FileType/binary, " using deprecated path rest endpoint">>,
              type = rest_with_file_path,
              target_nodes = Providers,
              client_spec = ClientSpec,
              prepare_args_fun = ?GET_METADATA_DEPRECATED_PATH_REST_ARGS_FUN(MetadataType, FilePath, QsParameters),
              validate_result_fun = ValidateRestCallResultFun,
              data_spec = DataSpec
          },
          #scenario_spec{
              name = <<"Get ", MetadataType/binary, " metadata from ", FileType/binary, " using deprecated id rest endpoint">>,
              type = rest,
              target_nodes = Providers,
              client_spec = ClientSpec,
              prepare_args_fun = ?GET_METADATA_DEPRECATED_ID_REST_ARGS_FUN(MetadataType, FileObjectId, QsParameters),
              validate_result_fun = ValidateRestCallResultFun,
              data_spec = DataSpec
          },
          #scenario_spec{
              name = <<"Get ", MetadataType/binary, " metadata from ", FileType/binary, " using gs api">>,
              type = gs,
              target_nodes = Providers,
              client_spec = ClientSpec,
              prepare_args_fun = ?GET_METADATA_GS_ARGS_FUN(MetadataType, FileGuid, private),
              validate_result_fun = ValidateGsCallResultFun,
              data_spec = DataSpec
          }
      ]));
  get_metadata_test_base(
      MetadataType, FileType, _FilePath, FileGuid, ShareId,
      ValidateRestCallResultFun, ValidateGsCallResultFun,
      Providers, _ClientSpec, DataSpec, QsParameters, Config
  ) ->
      FileShareGuid = file_id:guid_to_share_guid(FileGuid, ShareId),
      {ok, FileShareObjectId} = file_id:guid_to_objectid(FileShareGuid),
  
      % Special case -> any user can make requests for shares but if request is
      % being made using credentials by user not supported on specific provider
      % ?ERROR_USER_NOT_SUPPORTED will be returned
      ClientSpec = #client_spec{
          correct = [?NOBODY, ?USER_IN_SPACE_1_AUTH, ?USER_IN_SPACE_2_AUTH, ?USER_IN_BOTH_SPACES_AUTH],
          unauthorized = [],
          forbidden = [],
          supported_clients_per_node = ?SUPPORTED_CLIENTS_PER_NODE(Config)
      },
  
      ?assert(api_test_utils:run_scenarios(Config, [
          #scenario_spec{
              name = <<"Get ", MetadataType/binary, " metadata from shared ", FileType/binary, " using rest endpoint">>,
              type = rest,
              target_nodes = Providers,
              client_spec = ClientSpec,
              prepare_args_fun = ?GET_METADATA_REST_ARGS_FUN(MetadataType, FileShareObjectId, QsParameters),
              validate_result_fun = ValidateRestCallResultFun,
              data_spec = DataSpec
          },
          #scenario_spec{
              name = <<"Get ", MetadataType/binary, " metadata from shared ", FileType/binary, " using deprecated id rest endpoint">>,
              type = rest,
              target_nodes = Providers,
              client_spec = ClientSpec,
              prepare_args_fun = ?GET_METADATA_DEPRECATED_ID_REST_ARGS_FUN(MetadataType, FileShareObjectId, QsParameters),
              validate_result_fun = ValidateRestCallResultFun,
              data_spec = DataSpec
          },
          #scenario_spec{
              name = <<"Get ", MetadataType/binary, " metadata from shared ", FileType/binary, " using gs public api">>,
              type = gs,
              target_nodes = Providers,
              client_spec = ClientSpec,
              prepare_args_fun = ?GET_METADATA_GS_ARGS_FUN(MetadataType, FileShareGuid, public),
              validate_result_fun = ValidateGsCallResultFun,
              data_spec = DataSpec
          },
          #scenario_spec{
              name = <<"Get ", MetadataType/binary, " metadata from shared ", FileType/binary, " using private gs api">>,
              type = gs,
              target_nodes = Providers,
              client_spec = ClientSpec,
              prepare_args_fun = ?GET_METADATA_GS_ARGS_FUN(MetadataType, FileShareGuid, private),
              validate_result_fun = fun(_, Result) ->
                  ?assertEqual(?ERROR_UNAUTHORIZED, Result)
              end,
              data_spec = DataSpec
          }
      ])).
  
  
  get_xattr_metadata_test(Config) ->
      [Provider2, Provider1] = ?config(op_worker_nodes, Config),
  
      GetSessionFun = fun(Node) ->
          ?config({session_id, {?USER_IN_BOTH_SPACES, ?GET_DOMAIN(Node)}}, Config)
      end,
  
      UserSessId = GetSessionFun(Provider2),
  
      Dir1Path = filename:join(["/", ?SPACE_2, ?SCENARIO_NAME]),
      {ok, Dir1Guid} = lfm_proxy:mkdir(Provider2, UserSessId, Dir1Path, 8#777),
      set_all_metadata_types(Provider2, UserSessId, Dir1Guid, set_1),
  
      Dir2Path = filename:join([Dir1Path, <<"dir_layer_4">>]),
      {ok, Dir2Guid} = lfm_proxy:mkdir(Provider2, UserSessId, Dir2Path, 8#717),
      {ok, ShareId} = lfm_proxy:create_share(Provider2, UserSessId, {guid, Dir2Guid}, <<"share">>),
  
      DirWithoutMetadataPath = filename:join([Dir2Path, <<"dir_without_metadata">>]),
      {ok, DirWithoutMetadataGuid} = lfm_proxy:mkdir(Provider2, UserSessId, DirWithoutMetadataPath, 8#777),
  
      DirWithMetadataPath = filename:join([Dir2Path, <<"dir_with_metadata">>]),
      {ok, DirWithMetadataGuid} = lfm_proxy:mkdir(Provider2, UserSessId, DirWithMetadataPath, 8#777),
      set_all_metadata_types(Provider2, UserSessId, DirWithMetadataGuid, set_2),
  
      RegularFileWithoutMetadataPath = filename:join([Dir2Path, <<"file_without_metadata">>]),
      {ok, RegularFileWithoutMetadataGuid} = lfm_proxy:create(Provider2, UserSessId, RegularFileWithoutMetadataPath, 8#777),
  
      RegularFileWithMetadataPath = filename:join([Dir2Path, <<"file_with_metadata">>]),
      {ok, RegularFileWithMetadataGuid} = lfm_proxy:create(Provider2, UserSessId, RegularFileWithMetadataPath, 8#777),
      set_all_metadata_types(Provider2, UserSessId, RegularFileWithMetadataGuid, set_2),
  
      % Wait for metadata sync between providers
      ?assertMatch(
          {ok, #file_attr{}},
          lfm_proxy:stat(Provider1, GetSessionFun(Provider1), {guid, RegularFileWithMetadataGuid}),
          ?ATTEMPTS
      ),
  
      NotSetXattrKey = <<"not_set_xattr">>,
  
      DataSpec = #data_spec{
          optional = [<<"attribute">>, <<"inherited">>, <<"show_internal">>],
          correct_values = #{
              <<"attribute">> => [
                  % Xattr name with prefixes 'cdmi_' and 'onedata_' should be forbidden
  
negative.code:         ]
      },
  
      get_metadata_test_base(
          <<"xattrs">>,
          FileType, FileLayer3Path, FileLayer3Guid, ShareId,
          create_validate_get_metadata_rest_call_fun(GetExpCallResultFun),
          create_validate_get_metadata_gs_call_fun(GetExpCallResultFun),
          _Providers = ?config(op_worker_nodes, Config),
          ClientSpec,
          DataSpec,
          QsParams,
          Config
      ).
  
  
  %%--------------------------------------------------------------------
  %% @private
  %% @doc
  %% Creates following directory structure:
  %%
  %%   TopDir (posix: 777) - ?ALL_METADATA_SET_1
  %%     |
  %%     |-- DirLayer2 (posix: 717, maybe shared) - no xattrs
  %%            |
  %%            |-- FileLayer3 (posix: 777) - ?ALL_METADATA_SET_2
  %% @end
  %%--------------------------------------------------------------------
  create_get_xattrs_tests_env(FileType, SetXattrs, CreateShare, Config) ->
      [P2, P1] = ?config(op_worker_nodes, Config),
      SessIdP1 = ?USER_IN_BOTH_SPACES_SESS_ID(P1, Config),
      SessIdP2 = ?USER_IN_BOTH_SPACES_SESS_ID(P2, Config),
  
      TopDirPath = filename:join(["/", ?SPACE_2, ?RANDOM_FILE_NAME]),
      {ok, TopDirGuid} = lfm_proxy:mkdir(P1, SessIdP1, TopDirPath, 8#777),
      set_all_metadata_types(P1, SessIdP1, TopDirGuid, set_1),
  
      DirLayer2Path = filename:join([TopDirPath, <<"dir_layer_2">>]),
      {ok, DirLayer2Guid} = lfm_proxy:mkdir(P1, SessIdP1, DirLayer2Path, 8#717),
      ShareId = case CreateShare of
          true ->
              {ok, Id} = lfm_proxy:create_share(P1, SessIdP1, {guid, DirLayer2Guid}, <<"share">>),
              Id;
          false ->
              undefined
      end,
  
      FileLayer3Path = filename:join([DirLayer2Path, ?RANDOM_FILE_NAME]),
      {ok, FileLayer3Guid} = create_file(FileType, P1, SessIdP1, FileLayer3Path),
      case SetXattrs of
          true ->
              set_all_metadata_types(P1, SessIdP1, FileLayer3Guid, set_2);
          false ->
              ok
      end,
  
      % Wait for metadata sync between providers
      ?assertMatch({ok, _}, lfm_proxy:stat(P2, SessIdP2, {guid, FileLayer3Guid}), ?ATTEMPTS),
  
      {FileLayer3Path, FileLayer3Guid, ShareId}.
  
  
  %%--------------------------------------------------------------------
  %% @private
  %% @doc
  %% Creates function returning expected result from get xattrs
  %% rest/gs call taking into account env created by
  %% create_get_xattrs_tests_env/4.
  %% @end
  %%--------------------------------------------------------------------
  create_get_xattrs_call_exp_result_fun(ShareId, DirectMetadataSet, NotSetXattrKey) ->
      fun(#api_test_ctx{client = Client, data = Data}) ->
          try
              Attribute = maps:get(<<"attribute">>, Data, undefined),
              IncludeInherited = maps:get(<<"inherited">>, Data, false),
  