Replace Bierman02 with RFC8040 for OpenFlow Plugin
[integration/test.git] / csit / libraries / TemplatedRequests.robot
index eece6288df2fe802a64f30230ea666ecafba003e..99a19b2332057d4d798c3708c983142698bf9d67 100644 (file)
@@ -1,13 +1,13 @@
 *** Settings ***
 Documentation     Resource for supporting http Requests based on data stored in files.
-...           
+...
 ...               Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
-...           
+...
 ...               This program and the accompanying materials are made available under the
 ...               terms of the Eclipse Public License v1.0 which accompanies this distribution,
 ...               and is available at http://www.eclipse.org/legal/epl-v10.html
-...           
-...           
+...
+...
 ...               The main strength of this library are *_As_*_Templated keywords
 ...               User gives a path to directory where files with templates for URI
 ...               and XML (or JSON) data are present, and a mapping with substitution to make;
@@ -16,12 +16,12 @@ Documentation     Resource for supporting http Requests based on data stored in
 ...               Simple example (tidy insists on single space where 4 spaces should be):
 ...               TemplatedRequests.Put_As_Json_Templated folder=${VAR_BASE}/person mapping={"NAME":"joe"}
 ...               TemplatedRequests.Get_As_Json_Templated folder=${VAR_BASE}/person mapping={"NAME":"joe"} verify=True
-...           
+...
 ...               In that example, we are PUTting "person" data with specified value for "NAME" placeholder.
 ...               We are not verifying PUT response (probably empty string which is not a valid JSON),
 ...               but we are issuing GET (same URI) and verifying the repsonse matches the same data.
 ...               Both lines are returning text response, but in the example we are not saving it into variable.
-...           
+...
 ...               Optionally, *_As_*_Templated keywords call verification of response.
 ...               There are separate Verify_* keywords, for users who use intermediate processing.
 ...               For JSON responses, there is a support for normalizing.
@@ -29,12 +29,12 @@ Documentation     Resource for supporting http Requests based on data stored in
 ...               *_Uri keywords do not use templates, but may be useful in general,
 ...               perhaps for users who call Resolve_Text_* keywords.
 ...               *_As_*_Uri are the less flexible but less argument-heavy versions of *_Uri keywords.
-...           
+...
 ...               This resource supports generating data with simple lists.
 ...               ${iterations} argument control number of items, "$i" will be substituted
 ...               automatically (not by the provided mapping) with integers starting with ${iter_start} (default 1).
 ...               For example "iterations=2 iter_start=3" will create items with i=3 and i=4.
-...           
+...
 ...               This implementation relies on file names to distinguish data.
 ...               Each file is expected to end in newline, compiled data has final newline removed.
 ...               Here is a table so that users can create their own templates:
@@ -48,7 +48,7 @@ Documentation     Resource for supporting http Requests based on data stored in
 ...               *.prolog.*: Temlate with data before iterated items.
 ...               *.item.*: Template with data piece corresponding to one item.
 ...               *.epilog.*: Temlate with data after iterated items.
-...           
+...
 ...               One typical use of this Resource is to make runtime changes to ODL configuration.
 ...               Different ODL parts have varying ways of configuration,
 ...               this library affects only the Config Subsystem way.
@@ -56,7 +56,7 @@ Documentation     Resource for supporting http Requests based on data stored in
 ...               a NETCONF server as its publicly available entry point.
 ...               Netconf-connector feature makes this netconf server available for RESTCONF calls.
 ...               Be careful to use appropriate feature, odl-netconf-connector* does not work in cluster.
-...           
+...
 ...               This Resource currently calls RequestsLibrary directly,
 ...               so it does not work with AuthStandalone or similar.
 ...               This Resource does not maintain any internal Sessions.
@@ -70,16 +70,16 @@ Documentation     Resource for supporting http Requests based on data stored in
 ...               both on session level (where it becomes a default value for requests) and on request
 ...               level (when present, it overrides the session value). To override the default
 ...               value keywords' http_timeout parameter may be used.
-...           
+...
 ...               These Keywords contain frequent BuiltIn.Log invocations,
 ...               so they are not suited for scale or performance suites.
 ...               And as usual, performance tests should use specialized utilities,
 ...               as Robot in general and this Resource specifically will be too slow.
-...           
+...
 ...               As this Resource makes assumptions about intended headers,
 ...               it is not flexible enough for suites specifically testing Restconf corner cases.
 ...               Also, list of allowed http status codes is quite rigid and broad.
-...           
+...
 ...               Rules for ordering Keywords within this Resource:
 ...               1. User friendlier Keywords first.
 ...               2. Get, Put, Post, Delete, Verify.
@@ -94,18 +94,18 @@ Documentation     Resource for supporting http Requests based on data stored in
 ...               Json is less prone to element ordering issues.
 ...               PUT does not fail on existing element, also it does not allow
 ...               shortened URIs (container instead keyed list element) as Post does.
-...           
+...
 ...               TODO: Add ability to override allowed status codes,
 ...               so that negative tests do not need to parse the failure message.
-...           
+...
 ...               TODO: Migrate suites to this Resource and remove *ViaRestconf Resources.
-...           
+...
 ...               TODO: Currently the verification step is only in *_As_*_Templated keywords.
 ...               It could be moved to "non-as" *_Templated ones,
 ...               but that would take even more horizontal space. Is it worth doing?
-...           
+...
 ...               TODO: Should iterations=0 be supported for JSON (remove [])?
-...           
+...
 ...               TODO: Currently, ${ACCEPT_EMPTY} is used for JSON-expecting requests.
 ...               perhaps explicit ${ACCEPT_JSON} will be better, even if it sends few bytes more?
 Library           Collections
@@ -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}