Replace Bierman02 with RFC8040 for OpenFlow Plugin
[integration/test.git] / csit / libraries / TemplatedRequests.robot
index 052080703a9f0e3fce314dac8be706ef6fa5b6d8..99a19b2332057d4d798c3708c983142698bf9d67 100644 (file)
@@ -120,7 +120,7 @@ Resource          ${CURDIR}/../variables/Variables.robot
 @{ALLOWED_DELETE_STATUS_CODES}    ${200}    ${201}    ${204}    ${404}    # List of integers, not strings. Used by DELETE if the resource may be not present.
 @{ALLOWED_STATUS_CODES}    ${200}    ${201}    ${204}    # List of integers, not strings. Used by both PUT and DELETE (if the resource should have been present).
 @{DATA_VALIDATION_ERROR}    ${400}    # For testing mildly negative scenarios where ODL reports user error.
-@{DELETED_STATUS_CODE}    ${404}    # List of integers, not strings. Used by DELETE if the resource may be not present.
+@{DELETED_STATUS_CODES}    ${404}    ${409}    # List of integers, not strings. Used by DELETE if the resource may be not present.
 # TODO: Add option for delete to require 404.
 @{INTERNAL_SERVER_ERROR}    ${500}    # Only for testing severely negative scenarios where ODL cannot recover.
 @{KEYS_WITH_BITS}    op    # the default list with keys to be sorted when norm_json libray is used
@@ -135,8 +135,8 @@ Create_Default_Session
     RequestsLibrary.Create_Session    alias=default    url=${url}    auth=${auth}    timeout=${timeout}    max_retries=${max_retries}
 
 Get_As_Json_Templated
-    [Arguments]    ${folder}    ${mapping}={}    ${session}=default    ${verify}=False    ${iterations}=${EMPTY}    ${iter_start}=1
-    ...    ${http_timeout}=${EMPTY}    ${log_response}=True
+    [Arguments]    ${folder}    ${mapping}=&{EMPTY}    ${session}=default    ${verify}=False    ${iterations}=${EMPTY}    ${iter_start}=1
+    ...    ${http_timeout}=${EMPTY}    ${log_response}=True    ${iter_j_offset}=0
     [Documentation]    Add arguments sensible for JSON data, return Get_Templated response text.
     ...    Optionally, verification against JSON data (may be iterated) is called.
     ...    Only subset of JSON data is verified and returned if JMES path is specified in
@@ -144,48 +144,50 @@ Get_As_Json_Templated
     ${response_text} =    Get_Templated    folder=${folder}    mapping=${mapping}    accept=${ACCEPT_EMPTY}    session=${session}    normalize_json=True
     ...    http_timeout=${http_timeout}    log_response=${log_response}
     BuiltIn.Run_Keyword_If    ${verify}    Verify_Response_As_Json_Templated    response=${response_text}    folder=${folder}    base_name=data    mapping=${mapping}
-    ...    iterations=${iterations}    iter_start=${iter_start}
+    ...    iterations=${iterations}    iter_start=${iter_start}    iter_j_offset=${iter_j_offset}
     [Return]    ${response_text}
 
 Get_As_Xml_Templated
-    [Arguments]    ${folder}    ${mapping}={}    ${session}=default    ${verify}=False    ${iterations}=${EMPTY}    ${iter_start}=1
-    ...    ${http_timeout}=${EMPTY}
+    [Arguments]    ${folder}    ${mapping}=&{EMPTY}    ${session}=default    ${verify}=False    ${iterations}=${EMPTY}    ${iter_start}=1
+    ...    ${http_timeout}=${EMPTY}    ${iter_j_offset}=0
     [Documentation]    Add arguments sensible for XML data, return Get_Templated response text.
     ...    Optionally, verification against XML data (may be iterated) is called.
     ${response_text} =    Get_Templated    folder=${folder}    mapping=${mapping}    accept=${ACCEPT_XML}    session=${session}    normalize_json=False
     ...    http_timeout=${http_timeout}
     BuiltIn.Run_Keyword_If    ${verify}    Verify_Response_As_Xml_Templated    response=${response_text}    folder=${folder}    base_name=data    mapping=${mapping}
-    ...    iterations=${iterations}    iter_start=${iter_start}
+    ...    iterations=${iterations}    iter_start=${iter_start}    iter_j_offset=${iter_j_offset}
     [Return]    ${response_text}
 
 Put_As_Json_Templated
-    [Arguments]    ${folder}    ${mapping}={}    ${session}=default    ${verify}=False    ${iterations}=${EMPTY}    ${iter_start}=1
-    ...    ${http_timeout}=${EMPTY}
+    [Arguments]    ${folder}    ${mapping}=&{EMPTY}    ${session}=default    ${verify}=False    ${iterations}=${EMPTY}    ${iter_start}=1
+    ...    ${http_timeout}=${EMPTY}    ${iter_j_offset}=0
     [Documentation]    Add arguments sensible for JSON data, return Put_Templated response text.
     ...    Optionally, verification against response.json (no iteration) is called.
     ...    Only subset of JSON data is verified and returned if JMES path is specified in
     ...    file ${folder}${/}jmespath.expr.
     ${response_text} =    Put_Templated    folder=${folder}    base_name=data    extension=json    accept=${ACCEPT_EMPTY}    content_type=${HEADERS_YANG_JSON}
     ...    mapping=${mapping}    session=${session}    normalize_json=True    endline=${\n}    iterations=${iterations}    iter_start=${iter_start}
-    ...    http_timeout=${http_timeout}
-    BuiltIn.Run_Keyword_If    ${verify}    Verify_Response_As_Json_Templated    response=${response_text}    folder=${folder}    base_name=response    mapping=${mapping}
+    ...    http_timeout=${http_timeout}    iter_j_offset=${iter_j_offset}
+    BuiltIn.Run_Keyword_If    ${verify}    Verify_Response_As_Json_Templated    response=${response_text}    folder=${folder}
+    ...    base_name=response    mapping=${mapping}    iter_j_offset=${iter_j_offset}
     [Return]    ${response_text}
 
 Put_As_Xml_Templated
-    [Arguments]    ${folder}    ${mapping}={}    ${session}=default    ${verify}=False    ${iterations}=${EMPTY}    ${iter_start}=1
-    ...    ${http_timeout}=${EMPTY}
+    [Arguments]    ${folder}    ${mapping}=&{EMPTY}    ${session}=default    ${verify}=False    ${iterations}=${EMPTY}    ${iter_start}=1
+    ...    ${http_timeout}=${EMPTY}    ${iter_j_offset}=0
     [Documentation]    Add arguments sensible for XML data, return Put_Templated response text.
     ...    Optionally, verification against response.xml (no iteration) is called.
     # In case of iterations, we use endlines in data to send, as it should not matter and it is more readable.
     ${response_text} =    Put_Templated    folder=${folder}    base_name=data    extension=xml    accept=${ACCEPT_XML}    content_type=${HEADERS_XML}
     ...    mapping=${mapping}    session=${session}    normalize_json=False    endline=${\n}    iterations=${iterations}    iter_start=${iter_start}
-    ...    http_timeout=${http_timeout}
-    BuiltIn.Run_Keyword_If    ${verify}    Verify_Response_As_Xml_Templated    response=${response_text}    folder=${folder}    base_name=response    mapping=${mapping}
+    ...    http_timeout=${http_timeout}    iter_j_offset=${iter_j_offset}
+    BuiltIn.Run_Keyword_If    ${verify}    Verify_Response_As_Xml_Templated    response=${response_text}    folder=${folder}
+    ...    base_name=response    mapping=${mapping}    iter_j_offset=${iter_j_offset}
     [Return]    ${response_text}
 
 Post_As_Json_Templated
-    [Arguments]    ${folder}    ${mapping}={}    ${session}=default    ${verify}=False    ${iterations}=${EMPTY}    ${iter_start}=1
-    ...    ${additional_allowed_status_codes}=${NO_STATUS_CODES}    ${explicit_status_codes}=${NO_STATUS_CODES}    ${http_timeout}=${EMPTY}
+    [Arguments]    ${folder}    ${mapping}=&{EMPTY}    ${session}=default    ${verify}=False    ${iterations}=${EMPTY}    ${iter_start}=1
+    ...    ${additional_allowed_status_codes}=${NO_STATUS_CODES}    ${explicit_status_codes}=${NO_STATUS_CODES}    ${http_timeout}=${EMPTY}    ${iter_j_offset}=0
     [Documentation]    Add arguments sensible for JSON data, return Post_Templated response text.
     ...    Optionally, verification against response.json (no iteration) is called.
     ...    Only subset of JSON data is verified and returned if JMES path is specified in
@@ -195,12 +197,14 @@ Post_As_Json_Templated
     ${response_text} =    Post_Templated    folder=${folder}    base_name=data    extension=json    accept=${ACCEPT_EMPTY}    content_type=${HEADERS_YANG_JSON}
     ...    mapping=${mapping}    session=${session}    normalize_json=True    endline=${\n}    iterations=${iterations}    iter_start=${iter_start}
     ...    additional_allowed_status_codes=${additional_allowed_status_codes}    explicit_status_codes=${explicit_status_codes}    http_timeout=${http_timeout}
-    BuiltIn.Run_Keyword_If    ${verify}    Verify_Response_As_Json_Templated    response=${response_text}    folder=${folder}    base_name=response    mapping=${mapping}
+    ...    iter_j_offset=${iter_j_offset}
+    BuiltIn.Run_Keyword_If    ${verify}    Verify_Response_As_Json_Templated    response=${response_text}    folder=${folder}
+    ...    base_name=response    mapping=${mapping}    iter_j_offset=${iter_j_offset}
     [Return]    ${response_text}
 
 Post_As_Json_Rfc8040_Templated
-    [Arguments]    ${folder}    ${mapping}={}    ${session}=default    ${verify}=False    ${iterations}=${EMPTY}    ${iter_start}=1
-    ...    ${additional_allowed_status_codes}=${NO_STATUS_CODES}    ${explicit_status_codes}=${NO_STATUS_CODES}    ${http_timeout}=${EMPTY}
+    [Arguments]    ${folder}    ${mapping}=&{EMPTY}    ${session}=default    ${verify}=False    ${iterations}=${EMPTY}    ${iter_start}=1
+    ...    ${additional_allowed_status_codes}=${NO_STATUS_CODES}    ${explicit_status_codes}=${NO_STATUS_CODES}    ${http_timeout}=${EMPTY}    ${iter_j_offset}=0
     [Documentation]    Add arguments sensible for JSON data, return Post_Templated response text.
     ...    Optionally, verification against response.json (no iteration) is called.
     ...    Only subset of JSON data is verified and returned if JMES path is specified in
@@ -212,41 +216,45 @@ Post_As_Json_Rfc8040_Templated
     ${response_text} =    Post_Templated    folder=${folder}    base_name=data    extension=json    accept=${ACCEPT_EMPTY}    content_type=${HEADERS_YANG_RFC8040_JSON}
     ...    mapping=${mapping}    session=${session}    normalize_json=True    endline=${\n}    iterations=${iterations}    iter_start=${iter_start}
     ...    additional_allowed_status_codes=${additional_allowed_status_codes}    explicit_status_codes=${explicit_status_codes}    http_timeout=${http_timeout}
+    ...    iter_j_offset=${iter_j_offset}
     BuiltIn.Run_Keyword_If    ${verify}    Verify_Response_As_Json_Templated    response=${response_text}    folder=${folder}    base_name=response    mapping=${mapping}
+    ...    iter_j_offset=${iter_j_offset}
     [Return]    ${response_text}
 
 Post_As_Xml_Templated
-    [Arguments]    ${folder}    ${mapping}={}    ${session}=default    ${verify}=False    ${iterations}=${EMPTY}    ${iter_start}=1
-    ...    ${additional_allowed_status_codes}=${NO_STATUS_CODES}    ${explicit_status_codes}=${NO_STATUS_CODES}    ${http_timeout}=${EMPTY}
+    [Arguments]    ${folder}    ${mapping}=&{EMPTY}    ${session}=default    ${verify}=False    ${iterations}=${EMPTY}    ${iter_start}=1
+    ...    ${additional_allowed_status_codes}=${NO_STATUS_CODES}    ${explicit_status_codes}=${NO_STATUS_CODES}    ${http_timeout}=${EMPTY}    ${iter_j_offset}=0
     [Documentation]    Add arguments sensible for XML data, return Post_Templated response text.
     ...    Optionally, verification against response.xml (no iteration) is called.
     # In case of iterations, we use endlines in data to send, as it should not matter and it is more readable.
     ${response_text} =    Post_Templated    folder=${folder}    base_name=data    extension=xml    accept=${ACCEPT_XML}    content_type=${HEADERS_XML}
     ...    mapping=${mapping}    session=${session}    normalize_json=False    endline=${\n}    iterations=${iterations}    iter_start=${iter_start}
     ...    additional_allowed_status_codes=${additional_allowed_status_codes}    explicit_status_codes=${explicit_status_codes}    http_timeout=${http_timeout}
+    ...    iter_j_offset=${iter_j_offset}
     BuiltIn.Run_Keyword_If    ${verify}    Verify_Response_As_Xml_Templated    response=${response_text}    folder=${folder}    base_name=response    mapping=${mapping}
+    ...    iter_j_offset=${iter_j_offset}
     [Return]    ${response_text}
 
 Delete_Templated
-    [Arguments]    ${folder}    ${mapping}={}    ${session}=default    ${additional_allowed_status_codes}=${NO_STATUS_CODES}    ${http_timeout}=${EMPTY}    ${location}=location
+    [Arguments]    ${folder}    ${mapping}=&{EMPTY}    ${session}=default    ${additional_allowed_status_codes}=${NO_STATUS_CODES}    ${http_timeout}=${EMPTY}    ${location}=location
     [Documentation]    Resolve URI from folder, issue DELETE request.
-    ${uri} =    Resolve_Text_From_Template_Folder    folder=${folder}    base_name=${location}    extension=uri    mapping=${mapping}
+    ${uri} =    Resolve_Text_From_Template_Folder    folder=${folder}    base_name=${location}    extension=uri    mapping=${mapping}    percent_encode=True
     ${response_text} =    Delete_From_Uri    uri=${uri}    session=${session}    additional_allowed_status_codes=${additional_allowed_status_codes}    http_timeout=${http_timeout}
     [Return]    ${response_text}
 
 Verify_Response_As_Json_Templated
-    [Arguments]    ${response}    ${folder}    ${base_name}=response    ${mapping}={}    ${iterations}=${EMPTY}    ${iter_start}=1
+    [Arguments]    ${response}    ${folder}    ${base_name}=response    ${mapping}=&{EMPTY}    ${iterations}=${EMPTY}    ${iter_start}=1    ${iter_j_offset}=0
     [Documentation]    Resolve expected JSON data, should be equal to provided \${response}.
     ...    JSON normalization is used, endlines enabled for readability.
     Verify_Response_Templated    response=${response}    folder=${folder}    base_name=${base_name}    extension=json    mapping=${mapping}    normalize_json=True
-    ...    endline=${\n}    iterations=${iterations}    iter_start=${iter_start}
+    ...    endline=${\n}    iterations=${iterations}    iter_start=${iter_start}    iter_j_offset=${iter_j_offset}
 
 Verify_Response_As_Xml_Templated
-    [Arguments]    ${response}    ${folder}    ${base_name}=response    ${mapping}={}    ${iterations}=${EMPTY}    ${iter_start}=1
+    [Arguments]    ${response}    ${folder}    ${base_name}=response    ${mapping}=&{EMPTY}    ${iterations}=${EMPTY}    ${iter_start}=1    ${iter_j_offset}=0
     [Documentation]    Resolve expected XML data, should be equal to provided \${response}.
     ...    Endline set to empty, as this Resource does not support indented XML comparison.
     Verify_Response_Templated    response=${response}    folder=${folder}    base_name=${base_name}    extension=xml    mapping=${mapping}    normalize_json=False
-    ...    endline=${EMPTY}    iterations=${iterations}    iter_start=${iter_start}
+    ...    endline=${EMPTY}    iterations=${iterations}    iter_start=${iter_start}    iter_j_offset=${iter_j_offset}
 
 Get_As_Json_From_Uri
     [Arguments]    ${uri}    ${session}=default    ${http_timeout}=${EMPTY}    ${log_response}=True
@@ -321,9 +329,9 @@ Resolve_Volatiles_Path
     [Return]    ${volatiles_list}
 
 Get_Templated
-    [Arguments]    ${folder}    ${accept}    ${mapping}={}    ${session}=default    ${normalize_json}=False    ${http_timeout}=${EMPTY}    ${log_response}=True
+    [Arguments]    ${folder}    ${accept}    ${mapping}=&{EMPTY}    ${session}=default    ${normalize_json}=False    ${http_timeout}=${EMPTY}    ${log_response}=True
     [Documentation]    Resolve URI from folder, call Get_From_Uri, return response text.
-    ${uri} =    Resolve_Text_From_Template_Folder    folder=${folder}    base_name=location    extension=uri    mapping=${mapping}
+    ${uri} =    Resolve_Text_From_Template_Folder    folder=${folder}    base_name=location    extension=uri    mapping=${mapping}    percent_encode=True
     ${jmes_expression} =    Resolve_Jmes_Path    ${folder}
     ${volatiles_list}=    Resolve_Volatiles_Path    ${folder}
     ${response_text} =    Get_From_Uri    uri=${uri}    accept=${accept}    session=${session}    normalize_json=${normalize_json}    jmes_path=${jmes_expression}
@@ -331,38 +339,38 @@ Get_Templated
     [Return]    ${response_text}
 
 Put_Templated
-    [Arguments]    ${folder}    ${base_name}    ${extension}    ${content_type}    ${accept}    ${mapping}={}
-    ...    ${session}=default    ${normalize_json}=False    ${endline}=${\n}    ${iterations}=${EMPTY}    ${iter_start}=1    ${http_timeout}=${EMPTY}
+    [Arguments]    ${folder}    ${base_name}    ${extension}    ${content_type}    ${accept}    ${mapping}=&{EMPTY}
+    ...    ${session}=default    ${normalize_json}=False    ${endline}=${\n}    ${iterations}=${EMPTY}    ${iter_start}=1    ${http_timeout}=${EMPTY}    ${iter_j_offset}=0
     [Documentation]    Resolve URI and data from folder, call Put_To_Uri, return response text.
-    ${uri} =    Resolve_Text_From_Template_Folder    folder=${folder}    base_name=location    extension=uri    mapping=${mapping}
+    ${uri} =    Resolve_Text_From_Template_Folder    folder=${folder}    base_name=location    extension=uri    mapping=${mapping}    percent_encode=True
     ${data} =    Resolve_Text_From_Template_Folder    folder=${folder}    base_name=${base_name}    extension=${extension}    mapping=${mapping}    endline=${endline}
-    ...    iterations=${iterations}    iter_start=${iter_start}
+    ...    iterations=${iterations}    iter_start=${iter_start}    iter_j_offset=${iter_j_offset}
     ${jmes_expression} =    Resolve_Jmes_Path    ${folder}
     ${response_text} =    Put_To_Uri    uri=${uri}    data=${data}    content_type=${content_type}    accept=${accept}    session=${session}
     ...    http_timeout=${http_timeout}    normalize_json=${normalize_json}    jmes_path=${jmes_expression}
     [Return]    ${response_text}
 
 Post_Templated
-    [Arguments]    ${folder}    ${base_name}    ${extension}    ${content_type}    ${accept}    ${mapping}={}
+    [Arguments]    ${folder}    ${base_name}    ${extension}    ${content_type}    ${accept}    ${mapping}=&{EMPTY}
     ...    ${session}=default    ${normalize_json}=False    ${endline}=${\n}    ${iterations}=${EMPTY}    ${iter_start}=1    ${additional_allowed_status_codes}=${NO_STATUS_CODES}
-    ...    ${explicit_status_codes}=${NO_STATUS_CODES}    ${http_timeout}=${EMPTY}
+    ...    ${explicit_status_codes}=${NO_STATUS_CODES}    ${http_timeout}=${EMPTY}    ${iter_j_offset}=0
     [Documentation]    Resolve URI and data from folder, call Post_To_Uri, return response text.
-    ${uri} =    Resolve_Text_From_Template_Folder    folder=${folder}    base_name=location    extension=uri    mapping=${mapping}
+    ${uri} =    Resolve_Text_From_Template_Folder    folder=${folder}    base_name=location    extension=uri    mapping=${mapping}    percent_encode=True
     ${data} =    Resolve_Text_From_Template_Folder    folder=${folder}    name_prefix=post_    base_name=${base_name}    extension=${extension}    mapping=${mapping}
-    ...    endline=${endline}    iterations=${iterations}    iter_start=${iter_start}
+    ...    endline=${endline}    iterations=${iterations}    iter_start=${iter_start}    iter_j_offset=${iter_j_offset}
     ${jmes_expression} =    Resolve_Jmes_Path    ${folder}
     ${response_text} =    Post_To_Uri    uri=${uri}    data=${data}    content_type=${content_type}    accept=${accept}    session=${session}
     ...    jmes_path=${jmes_expression}    normalize_json=${normalize_json}    additional_allowed_status_codes=${additional_allowed_status_codes}    explicit_status_codes=${explicit_status_codes}    http_timeout=${http_timeout}
     [Return]    ${response_text}
 
 Verify_Response_Templated
-    [Arguments]    ${response}    ${folder}    ${base_name}    ${extension}    ${mapping}={}    ${normalize_json}=False
-    ...    ${endline}=${\n}    ${iterations}=${EMPTY}    ${iter_start}=1
+    [Arguments]    ${response}    ${folder}    ${base_name}    ${extension}    ${mapping}=&{EMPTY}    ${normalize_json}=False
+    ...    ${endline}=${\n}    ${iterations}=${EMPTY}    ${iter_start}=1    ${iter_j_offset}=0
     [Documentation]    Resolve expected text from template, provided response shuld be equal.
     ...    If \${normalize_json}, perform normalization before comparison.
     # TODO: Support for XML-aware comparison could be added, but there are issues with namespaces and similar.
     ${expected_text} =    Resolve_Text_From_Template_Folder    folder=${folder}    base_name=${base_name}    extension=${extension}    mapping=${mapping}    endline=${endline}
-    ...    iterations=${iterations}    iter_start=${iter_start}
+    ...    iterations=${iterations}    iter_start=${iter_start}    iter_j_offset=${iter_j_offset}
     BuiltIn.Run_Keyword_And_Return_If    """${expected_text}""" == """${EMPTY}"""    BuiltIn.Should_Be_Equal    ${EMPTY}    ${response}
     BuiltIn.Run_Keyword_If    ${normalize_json}    Normalize_Jsons_And_Compare    expected_raw=${expected_text}    actual_raw=${response}
     ...    ELSE    BuiltIn.Should_Be_Equal    ${expected_text}    ${response}
@@ -452,23 +460,26 @@ Join_Two_Headers
     [Return]    ${accumulator}
 
 Resolve_Text_From_Template_Folder
-    [Arguments]    ${folder}    ${name_prefix}=${EMPTY}    ${base_name}=data    ${extension}=json    ${mapping}={}    ${iterations}=${EMPTY}
-    ...    ${iter_start}=1    ${endline}=${\n}
+    [Arguments]    ${folder}    ${name_prefix}=${EMPTY}    ${base_name}=data    ${extension}=json    ${mapping}=${EMPTY}    ${iterations}=${EMPTY}
+    ...    ${iter_start}=1    ${iter_j_offset}=0    ${endline}=${\n}    ${percent_encode}=False
     [Documentation]    Read a template from folder, strip endline, make changes according to mapping, return the result.
     ...    If \${iterations} value is present, put text together from "prolog", "item" and "epilog" parts,
     ...    where additional template variable ${i} goes from ${iter_start}, by one ${iterations} times.
+    ...    Template variable ${j} is calculated as ${i} incremented by offset ${iter_j_offset} ( j = i + iter_j_offset )
+    ...    used to create non uniform data in order to be able to validate UPDATE operations.
     ...    POST (as opposed to PUT) needs slightly different data, \${name_prefix} may be used to distinguish.
     ...    (Actually, it is GET who formats data differently when URI is a top-level container.)
-    BuiltIn.Run_Keyword_And_Return_If    not "${iterations}"    Resolve_Text_From_Template_File    folder=${folder}    file_name=${name_prefix}${base_name}.${extension}    mapping=${mapping}
-    ${prolog} =    Resolve_Text_From_Template_File    folder=${folder}    file_name=${name_prefix}${base_name}.prolog.${extension}    mapping=${mapping}
-    ${epilog} =    Resolve_Text_From_Template_File    folder=${folder}    file_name=${name_prefix}${base_name}.epilog.${extension}    mapping=${mapping}
+    BuiltIn.Run_Keyword_And_Return_If    not "${iterations}"    Resolve_Text_From_Template_File    folder=${folder}    file_name=${name_prefix}${base_name}.${extension}    mapping=${mapping}    percent_encode=${percent_encode}
+    ${prolog} =    Resolve_Text_From_Template_File    folder=${folder}    file_name=${name_prefix}${base_name}.prolog.${extension}    mapping=${mapping}    percent_encode=${percent_encode}
+    ${epilog} =    Resolve_Text_From_Template_File    folder=${folder}    file_name=${name_prefix}${base_name}.epilog.${extension}    mapping=${mapping}    percent_encode=${percent_encode}
     # Even POST uses the same item template (except indentation), so name prefix is ignored.
     ${item_template} =    Resolve_Text_From_Template_File    folder=${folder}    file_name=${base_name}.item.${extension}    mapping=${mapping}
     ${items} =    BuiltIn.Create_List
     ${separator} =    BuiltIn.Set_Variable_If    '${extension}' != 'json'    ${endline}    ,${endline}
     FOR    ${iteration}    IN RANGE    ${iter_start}    ${iterations}+${iter_start}
         BuiltIn.Run_Keyword_If    ${iteration} > ${iter_start}    Collections.Append_To_List    ${items}    ${separator}
-        ${item} =    BuiltIn.Evaluate    string.Template('''${item_template}''').substitute({"i":"${iteration}"})    modules=string
+        ${j} =    BuiltIn.Evaluate    ${iteration}+${iter_j_offset}
+        ${item} =    BuiltIn.Evaluate    string.Template('''${item_template}''').substitute({"i":"${iteration}", "j":${j}})    modules=string
         Collections.Append_To_List    ${items}    ${item}
         # TODO: The following makes ugly result for iterations=0. Should we fix that?
     END
@@ -477,7 +488,7 @@ Resolve_Text_From_Template_Folder
     [Return]    ${final_text}
 
 Resolve_Text_From_Template_File
-    [Arguments]    ${folder}    ${file_name}    ${mapping}={}
+    [Arguments]    ${folder}    ${file_name}    ${mapping}=&{EMPTY}    ${percent_encode}=False
     [Documentation]    Check if ${folder}.${ODL_STREAM}/${file_name} exists. If yes read and Log contents of file ${folder}.${ODL_STREAM}/${file_name},
     ...    remove endline, perform safe substitution, return result.
     ...    If no do it with the default ${folder}/${file_name}.
@@ -486,7 +497,9 @@ Resolve_Text_From_Template_File
     ${file_path}=    BuiltIn.Set Variable If    ${file_stream_exists}    ${file_path_stream}    ${folder}${/}${file_name}
     ${template} =    OperatingSystem.Get_File    ${file_path}
     BuiltIn.Log    ${template}
-    ${final_text} =    BuiltIn.Evaluate    string.Template('''${template}'''.rstrip()).safe_substitute(${mapping})    modules=string
+    ${mapping_to_use} =    BuiltIn.Run_Keyword_If    ${percent_encode} == True    Encode_Mapping    ${mapping}
+    ...    ELSE    BuiltIn.Set_Variable    ${mapping}
+    ${final_text} =    BuiltIn.Evaluate    string.Template('''${template}'''.rstrip()).safe_substitute(${mapping_to_use})    modules=string
     # Final text is logged where used.
     [Return]    ${final_text}
 
@@ -505,3 +518,19 @@ Normalize_Jsons_With_Bits_And_Compare
     ${expected_normalized} =    norm_json.normalize_json_text    ${expected_raw}    keys_with_bits=${keys_with_bits}
     ${actual_normalized} =    norm_json.normalize_json_text    ${actual_raw}    keys_with_bits=${keys_with_bits}
     BuiltIn.Should_Be_Equal    ${expected_normalized}    ${actual_normalized}
+
+Encode_Mapping
+    [Arguments]    ${mapping}
+    BuiltIn.Log    mapping: ${mapping}
+    ${encoded_mapping} =    BuiltIn.Create_Dictionary
+    FOR    ${key}    ${value}    IN    &{mapping}
+        ${encoded_value} =    Percent_Encode_String    ${value}
+        Collections.Set_To_Dictionary    ${encoded_mapping}    ${key}    ${encoded_value}
+    END
+    [Return]    ${encoded_mapping}
+
+Percent_Encode_String
+    [Arguments]    ${value}
+    [Documentation]    Percent encodes reserved characters in the given string so it can be used as part of url.
+    ${encoded} =    String.Replace_String_Using_Regexp    ${value}    :    %3A
+    [Return]    ${encoded}