Fix ConfigViaRestconf sometimes causing suite failure
[integration/test.git] / csit / libraries / ConfigViaRestconf.robot
1 *** Settings ***
2 Documentation     Robot keyword library (Resource) for runtime changes to config subsystem state using restconf calls.
3 ...
4 ...               Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
5 ...
6 ...               This program and the accompanying materials are made available under the
7 ...               terms of the Eclipse Public License v1.0 which accompanies this distribution,
8 ...               and is available at http://www.eclipse.org/legal/epl-v10.html
9 ...
10 ...
11 ...               The purpose of this library is to make runtime changes to ODL configuration
12 ...               easier from Robot suite contributor point of view.
13 ...
14 ...               Different ODL parts have varying ways of configuration,
15 ...               this library affects only the Config Subsystem way.
16 ...               Config Subsystem has (apart Java APIs mostly available only from inside of ODL)
17 ...               NETCONF server as its publicly available entry point.
18 ...               Netconf-connector feature makes this netconf server available for RESTCONF calls.
19 ...               Unfortunately, URIs and data payloads tend to be quite convoluted,
20 ...               so using RequestsLibrary directly from test cases is unwieldy.
21 ...
22 ...               The main strength of this library are *_Template_Folder_Config_Via_Restconf keywords
23 ...               User gives a path to directory where files with templates for URI fragment
24 ...               and XML (or JSON) data are present, and a mapping with substitution to make;
25 ...               the keywords will take it from there.
26 ...
27 ...               Prerequisities:
28 ...               * netconf-connector feature installed on ODL.
29 ...               * Setup_Config_Via_Restconf called from suite Setup once
30 ...               (or before any other keyword from this library, but just once).
31 Library           OperatingSystem
32 Library           RequestsLibrary
33 Library           String
34 Library           ${CURDIR}/HsfJson/hsf_json.py
35 Variables         ${CURDIR}/../variables/Variables.py
36
37 *** Variables ***
38 # TODO: Make the following list more narrow when Bug 2594 is fixed.
39 @{allowed_status_codes}    ${200}    ${201}    ${204}    # List of integers, not strings. Used by both PUT and DELETE.
40 ${cvr_workspace}    /tmp
41
42 *** Keywords ***
43 Setup_Config_Via_Restconf
44     [Documentation]    Creates Requests session to be used by subsequent keywords.
45     ...    Also remembers worspace to use when needed and two temp files for JSON data.
46     # Do not append slash at the end uf URL, Requests would add another, resulting in error.
47     RequestsLibrary.Create_Session    cvr_session    http://${CONTROLLER}:${RESTCONFPORT}${CONTROLLER_CONFIG_MOUNT}    headers=${HEADERS_XML}    auth=${AUTH}
48     ${workspace_defined}    BuiltIn.Run_Keyword_And_return_Status    BuiltIn.Variable_Should_Exist    ${WORKSPACE}
49     BuiltIn.Run_Keyword_If    ${workspace_defined}    BuiltIn.Set_Suite_Variable    ${cvr_workspace}    ${WORKSPACE}
50     BuiltIn.Set_Suite_Variable    ${cvr_actfile}    ${cvr_workspace}${/}actual.json
51     BuiltIn.Set_Suite_Variable    ${cvr_expfile}    ${cvr_workspace}${/}expected.json
52
53 Teardown_Config_Via_Restconf
54     [Documentation]    Teardown to pair with Setup (otherwise no-op).
55     BuiltIn.Comment    TODO: The following line does not seem to be implemented by RequestsLibrary. Look for a workaround.
56     BuiltIn.Comment    Delete_Session    cvr_session
57
58 Put_Xml_Template_Folder_Config_Via_Restconf
59     [Arguments]    ${folder}    ${mapping_as_string}={}
60     [Documentation]    Resolve URI and data from folder, PUT to controller config.
61     ${uri_part}=    Resolve_URI_From_Template_Folder    ${folder}    ${mapping_as_string}
62     ${xml_data}=    Resolve_Xml_Data_From_Template_Folder    ${folder}    ${mapping_as_string}
63     Put_Xml_Config_Via_Restconf    ${uri_part}    ${xml_data}
64
65 Get_Xml_Template_Folder_Config_Via_Restconf
66     [Arguments]    ${folder}    ${mapping_as_string}={}
67     [Documentation]    Resolve URI from folder, GET from controller config in XML form.
68     ${uri_part}=    Resolve_URI_From_Template_Folder    ${folder}    ${mapping_as_string}
69     ${xml_data}=    Get_Xml_Config_Via_Restconf    ${uri_part}
70     [Return]    ${xml_data}
71
72 Get_Json_Template_Folder_Config_Via_Restconf
73     [Arguments]    ${folder}    ${mapping_as_string}={}
74     [Documentation]    Resolve URI from folder, GET from controller config in JSON form.
75     ${uri_part}=    Resolve_URI_From_Template_Folder    ${folder}    ${mapping_as_string}
76     ${json_string}=    Get_Json_Config_Via_Restconf    ${uri_part}
77     [Return]    ${json_string}
78
79 Verify_Xml_Template_Folder_Config_Via_Restconf
80     [Arguments]    ${folder}    ${mapping_as_string}={}
81     [Documentation]    Resolve URI from folder, GET from controller config, compare to expected data.
82     # FIXME: This is subject to pseudorandom field ordering issue, use with care.
83     ${expected_data}=    Resolve_Xml_Data_From_Template_Folder    ${folder}    ${mapping_as_string}
84     ${actual_data}=    Get_Xml_Template_Folder_Config_Via_Restconf    ${folder}    ${mapping_as_string}
85     BuiltIn.Should_Be_Equal    ${actual_data}    ${expected_data}
86
87 Verify_Json_Template_Folder_Config_Via_Restconf
88     [Arguments]    ${folder}    ${mapping_as_string}={}
89     [Documentation]    Resolve URI from folder, GET from controller config, compare to expected data as normalized JSONs.
90     ${expected}=    Resolve_Json_Data_From_Template_Folder    ${folder}    ${mapping_as_string}
91     ${actual}=    Get_Json_Template_Folder_Config_Via_Restconf    ${folder}    ${mapping_as_string}
92     Normalize_Jsons_And_Compare    ${actual}    ${expected}
93
94 Normalize_Jsons_And_Compare
95     [Arguments]    ${actual_raw}    ${expected_raw}
96     [Documentation]    Use HsfJson to normalize both arguments, compute and Log diff, fail if diff is non-empty.
97     ...    This keywords assumes ${WORKSPACE} is defined as a suite variable.
98     ${actual_normalized}=    hsf_json.Hsf_Json    ${actual_raw}
99     ${expected_normalized}=    hsf_json.Hsf_Json    ${expected_raw}
100     OperatingSystem.Create_File    ${cvr_expfile}    ${expected_normalized}
101     OperatingSystem.Create_File    ${cvr_actfile}    ${actual_normalized}
102     ${diff}=    OperatingSystem.Run    diff -du '${cvr_expfile}' '${cvr_actfile}'
103     BuiltIn.Log    ${diff}
104     BuiltIn.Should_Be_Empty    ${diff}
105
106 Delete_Xml_Template_Folder_Config_Via_Restconf
107     [Arguments]    ${folder}    ${mapping_as_string}={}
108     [Documentation]    Resolve URI from folder, DELETE from controller config.
109     ${uri_part}=    Resolve_URI_From_Template_Folder    ${folder}    ${mapping_as_string}
110     Delete_Config_Via_Restconf    ${uri_part}
111
112 Resolve_URI_From_Template_Folder
113     [Arguments]    ${folder}    ${mapping_as_string}
114     [Documentation]    Read URI template from folder, strip endline, make changes according to mapping, return the result.
115     ${uri_template}=    OperatingSystem.Get_File    ${folder}${/}config.uri
116     BuiltIn.Log    ${uri_template}
117     ${uri_part}=    Strip_Endline_And_Apply_Substitutions_From_Mapping    ${uri_template}    ${mapping_as_string}
118     [Return]    ${uri_part}
119
120 Resolve_Xml_Data_From_Template_Folder
121     [Arguments]    ${folder}    ${mapping_as_string}
122     [Documentation]    Read XML data template from folder, strip endline, make changes according to mapping, return the result.
123     ${data_template}=    OperatingSystem.Get_File    ${folder}${/}data.xml
124     BuiltIn.Log    ${data_template}
125     ${xml_data}=    Strip_Endline_And_Apply_Substitutions_From_Mapping    ${data_template}    ${mapping_as_string}
126     [Return]    ${xml_data}
127
128 Resolve_Json_Data_From_Template_Folder
129     [Arguments]    ${folder}    ${mapping_as_string}
130     [Documentation]    Read JSON data template from folder, strip endline, make changes according to mapping, return the result.
131     ${data_template}=    OperatingSystem.Get_File    ${folder}${/}data.json
132     BuiltIn.Log    ${data_template}
133     ${json_data}=    Strip_Endline_And_Apply_Substitutions_From_Mapping    ${data_template}    ${mapping_as_string}
134     [Return]    ${json_data}
135
136 Strip_Endline_And_Apply_Substitutions_From_Mapping
137     [Arguments]    ${template_as_string}    ${mapping_as_string}
138     [Documentation]    Strip endline, apply substitutions, Log and return the result.
139     # Robot Framework does not understand dictionaries well, so resort to Evaluate.
140     # Needs python module "string", and since the template string is expected to contain newline, it has to be enclosed in triple quotes.
141     # Using rstrip() removes all trailing whitespace, which is what we want if there is something more than an endline.
142     ${final_text}=    BuiltIn.Evaluate    string.Template('''${template_as_string}'''.rstrip()).substitute(${mapping_as_string})    modules=string
143     BuiltIn.Log    ${final_text}
144     [Return]    ${final_text}
145
146 Put_Xml_Config_Module_Via_Restconf
147     [Arguments]    ${xml_data}    ${type}    ${name}
148     [Documentation]    Put new XML configuration to config:modules URI based on given module type and name.
149     # Also no slash here
150     Put_Xml_Config_Via_Restconf    config:modules/module/${type}/${name}    ${xml_data}
151
152 Put_Xml_Config_Service_Via_Restconf
153     [Arguments]    ${xml_data}    ${type}    ${name}
154     [Documentation]    Put new XML configuration to config:services URI based on given service type and instance name.
155     Put_Xml_Config_Via_Restconf    config:services/service/${type}/config:instance/${name}    ${xml_data}
156
157 Put_Xml_Config_Via_Restconf
158     [Arguments]    ${uri_part}    ${xml_data}
159     [Documentation]    Put XML data to given controller-config URI, check reponse text is empty and status_code is one of allowed ones.
160     BuiltIn.Log    ${uri_part}
161     BuiltIn.Log    ${xml_data}
162     ${response}=    RequestsLibrary.Put    cvr_session    ${uri_part}    data=${xml_data}
163     BuiltIn.Log    ${response.text}
164     BuiltIn.Log    ${response.status_code}
165     BuiltIn.Should_Be_Empty    ${response.text}
166     BuiltIn.Should_Contain    ${allowed_status_codes}    ${response.status_code}
167
168 Get_Xml_Config_Via_Restconf
169     [Arguments]    ${uri_part}
170     [Documentation]    Get XML data from given controller-config URI, check status_code is one of allowed ones, return response text.
171     BuiltIn.Log    ${uri_part}
172     ${response}=    RequestsLibrary.Get    cvr_session    ${uri_part}    headers=${ACCEPT_XML}
173     BuiltIn.Log    ${response.text}
174     BuiltIn.Log    ${response.status_code}
175     BuiltIn.Should_Contain    ${allowed_status_codes}    ${response.status_code}
176     [Return]    ${response.text}
177
178 Get_Json_Config_Via_Restconf
179     [Arguments]    ${uri_part}
180     [Documentation]    Get XML data from given controller-config URI, check status_code is one of allowed ones, return response text.
181     BuiltIn.Log    ${uri_part}
182     ${response}=    RequestsLibrary.Get    cvr_session    ${uri_part}    headers=${ACCEPT_JSON}
183     BuiltIn.Log    ${response.text}
184     BuiltIn.Log    ${response.status_code}
185     BuiltIn.Should_Contain    ${allowed_status_codes}    ${response.status_code}
186     [Return]    ${response.text}
187
188 Delete_Config_Via_Restconf
189     [Arguments]    ${uri_part}
190     [Documentation]    Delete resource at controller-config URI, check reponse text is empty and status_code is 204.
191     BuiltIn.Log    ${uri_part}
192     ${response}=    RequestsLibrary.Delete    cvr_session    ${uri_part}
193     BuiltIn.Log    ${response.text}
194     BuiltIn.Should_Be_Empty    ${response.text}
195     BuiltIn.Should_Contain    ${allowed_status_codes}    ${response.status_code}
196
197 Post_Xml_Config_Module_Via_Restconf
198     [Arguments]    ${xml_data}
199     [Documentation]    Post new XML configuration to config:modules.
200     # Also no slash here
201     Post_Xml_Config_Via_Restconf    config:modules    ${xml_data}
202
203 Post_Xml_Config_Service_Via_Restconf
204     [Arguments]    ${xml_data}
205     [Documentation]    Post new XML configuration to config:services.
206     Post_Xml_Config_Via_Restconf    config:services    ${xml_data}
207
208 Post_Xml_Config_Via_Restconf
209     [Arguments]    ${uri_part}    ${xml_data}
210     [Documentation]    Post XML data to given controller-config URI, check reponse text is empty and status_code is 204.
211     # As seen in previous two Keywords, Post does not need long specific URI.
212     # But during Lithium development, Post ceased to do merge, so those Keywords do not work anymore.
213     # This Keyword can still be used with specific URI to create a new container and fail if a container was already present.
214     ${response}=    RequestsLibrary.Post_Request    cvr_session    ${uri_part}    data=${xml_data}
215     BuiltIn.Log    ${response.text}
216     BuiltIn.Should_Be_Empty    ${response.text}
217     BuiltIn.Should_Be_Equal_As_Strings    ${response.status_code}    204