VNFPerformanceManagementKeywords.robot 19.9 KB
Newer Older
1
2
3
*** Settings ***
Resource    environment/variables.txt
Resource    environment/subscriptions.txt
Giacomo Bernini's avatar
upd    
Giacomo Bernini committed
4
Resource    environment/individualSubscription.txt
5
Library    REST    ${VNFM_SCHEMA}://${VNFM_HOST}:${VNFM_PORT}    ssl_verify=false
6
Library    MockServerLibrary 
7
8
9
10
11
Library    OperatingSystem
Library    BuiltIn
Library    JSONLibrary
Library    Collections
Library    JSONSchemaLibrary    schemas/
12
13
Library    Process
Library    String  
14
15

*** Keywords ***
Giacomo Bernini's avatar
upd    
Giacomo Bernini committed
16
Get all VNF Performance Subscriptions
17
18
19
20
21
22
    [Documentation]    The client can use this method to query the list of active subscriptions to Performance management notifications
    ...    subscribed by the client.
    ...    This method shall follow the provisions specified in the tables 6.4.7.3.2-1 and 6.4.7.3.2-2 for URI query parameters,
    ...    request and response data structures, and response codes.
    Set headers    {"Accept": "application/json"}
    Set headers    {"Content-Type": "application/json"}
23
    Run Keyword If    ${AUTH_USAGE} == 1    Set Headers    {"${AUTHORIZATION_HEADER}":"${AUTHORIZATION_TOKEN}"}
24
25
26
27
28
29
30
31
32
33
34
35
    GET    ${apiRoot}/${apiName}/${apiVersion}/subscriptions
    ${output}=    Output    response
    Set Suite Variable    ${response}    ${output}
    # Integer    response status    200
    # Log    Received a 200 OK as expected
    # ${contentType}=    Output    response headers Content-Type
    # Should Contain    ${contentType}    application/json
    # ${result}=    Output    response body
    # Validate Json    PmSubscriptions.schema.json    ${result}
    # Log    Validated PmSubscription schema


Giacomo Bernini's avatar
upd    
Giacomo Bernini committed
36
 Get VNF Performance Subscriptions with attribute-based filters
37
38
39
40
41
    [Documentation]    The client can use this method to query the list of active subscriptions to Performance management notifications
    ...    subscribed by the client.
    ...    This method shall follow the provisions specified in the tables 6.4.7.3.2-1 and 6.4.7.3.2-2 for URI query parameters,
    ...    request and response data structures, and response codes.
    Set headers    {"Accept": "${ACCEPT_JSON}"}
42
    Run Keyword If    ${AUTH_USAGE} == 1    Set Headers    {"${AUTHORIZATION_HEADER}":"${AUTHORIZATION_TOKEN}"}
43
44
45
46
47
48
49
50
51
52
53
54
55
    GET    ${apiRoot}/${apiName}/${apiVersion}/subscriptions?${filter_ok}
    ${output}=    Output    response
    Set Suite Variable    ${response}    ${output}
    # Integer    response status    200
    # Log    Received a 200 OK as expected
    # ${contentType}=    Output    response headers Content-Type
    # Should Contain    ${contentType}    application/json
    # ${result}=    Output    response body
    # Validate Json    PmSubscriptions.schema.json    ${result}
    # Log    Validated PmSubscription schema    
    


Giacomo Bernini's avatar
upd    
Giacomo Bernini committed
56
Get VNF Performance Subscriptions with invalid attribute-based filters
57
58
59
60
61
    [Documentation]    The client can use this method to query the list of active subscriptions to Performance management notifications
    ...    subscribed by the client.
    ...    This method shall follow the provisions specified in the tables 6.4.7.3.2-1 and 6.4.7.3.2-2 for URI query parameters,
    ...    request and response data structures, and response codes.
    Set headers    {"Accept": "${ACCEPT_JSON}"}
62
    Run Keyword If    ${AUTH_USAGE} == 1    Set Headers    {"${AUTHORIZATION_HEADER}":"${AUTHORIZATION_TOKEN}"}
63
64
65
66
67
68
69
70
71
72
73
74
    GET    ${apiRoot}/${apiName}/${apiVersion}/subscriptions?${filter_ko}
    ${output}=    Output    response
    Set Suite Variable    ${response}    ${output}
    # Integer    response status    400
    # Log    Received a 400 Bad Request as expected
    # ${contentType}=    Output    response headers Content-Type
    # Should Contain    ${contentType}    application/json
    # ${result}=    Output    response body
    # Validate Json    ProblemDetails.schema.json    ${result}
    # Log    Validated ProblemDetails schema
    
    
Giacomo Bernini's avatar
upd    
Giacomo Bernini committed
75
Get VNF Performance Subscriptions with invalid resource endpoint
76
77
78
79
80
    [Documentation]    The client can use this method to query the list of active subscriptions to Performance management notifications
    ...    subscribed by the client.
    ...    This method shall follow the provisions specified in the tables 6.4.7.3.2-1 and 6.4.7.3.2-2 for URI query parameters,
    ...    request and response data structures, and response codes.
    Set headers    {"Accept": "${ACCEPT_JSON}"}
81
    Run Keyword If    ${AUTH_USAGE} == 1    Set Headers    {"${AUTHORIZATION_HEADER}":"${AUTHORIZATION_TOKEN}"}
82
83
84
85
86
87
88
89
90
91
92
93
94
    GET    ${apiRoot}/${apiName}/${apiVersion}/subscription
    ${output}=    Output    response
    Set Suite Variable    ${response}    ${output}
    # Integer    response status    404
    # Log    Received a 404 Not found as expected
    # ${contentType}=    Output    response headers Content-Type
    # Should Contain    ${contentType}    application/json
    # ${result}=    Output    response body
    # Validate Json    ProblemDetails.schema.json    ${result}
    # Log    Validated ProblemDetails schema    



Giacomo Bernini's avatar
upd    
Giacomo Bernini committed
95
Send Post Request for VNF Performance Subscription
96
97
98
99
100
101
102
103
104
105
106
    [Documentation]    The POST method creates a new subscription.
    ...    This method shall follow the provisions specified in the tables 6.4.7.3.1-1 and 6.4.7.3.1-2 for URI query parameters,
    ...    request and response data structures, and response codes.
    ...    Creation of two subscription resources with the same callbackURI and the same filter can result in performance
    ...    degradation and will provide duplicates of notifications to the NFVO, and might make sense only in very rare use cases.
    ...    Consequently, the VNFM may either allow creating a subscription resource if another subscription resource with the
    ...    same filter and callbackUri already exists (in which case it shall return the "201 Created" response code), or may decide
    ...    to not create a duplicate subscription resource (in which case it shall return a "303 See Other" response code referencing
    ...    the existing subscription resource with the same filter and callbackUri).
    Set headers    {"Content-Type": "${CONTENT_TYPE_JSON}"}
    Set headers    {"Accept": "${ACCEPT_JSON}"}
107
    Run Keyword If    ${AUTH_USAGE} == 1    Set Headers    {"${AUTHORIZATION_HEADER}":"${AUTHORIZATION_TOKEN}"}
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
    ${body}=    Get File    jsons/subscriptions.json
    ${body}=    Replace String    ${body}    \${callback_uri}    ${callback_uri}
    ${body}=    Replace String    ${body}    \${callback_port}    ${callback_port}
    ${body}=    Replace String    ${body}    \${callback_endpoint}    ${callback_endpoint}
    Log  Creating mock request and response to handle GET operation on notification endpoint
    &{notification_request}=  Create Mock Request Matcher	GET  ${callback_endpoint}
    &{notification_response}=  Create Mock Response	status_code=204
    Log    Issue the subscription request
    Create Mock Expectation  ${notification_request}  ${notification_response}
    Post    ${apiRoot}/${apiName}/${apiVersion}/subscriptions    ${body}    
	${output}=    Output    response
	Set Global Variable    ${response}    ${output}
	Clear Requests    ${callback_endpoint}
    #Run Keyword If    ${NFVO_CHECKS_NOTIF_ENDPOINT} == 1    #removed as the check of notif endpoint is done by NFVO while processing subscription reques
    #...    Check Notification Endpoint 
123
124


Giacomo Bernini's avatar
upd    
Giacomo Bernini committed
125
Send Post Request for Duplicated VNF Performance Subscription
126
127
128
129
130
131
132
133
134
135
136
    [Documentation]    The POST method creates a new subscription.
    ...    This method shall follow the provisions specified in the tables 6.4.7.3.1-1 and 6.4.7.3.1-2 for URI query parameters,
    ...    request and response data structures, and response codes.
    ...    Creation of two subscription resources with the same callbackURI and the same filter can result in performance
    ...    degradation and will provide duplicates of notifications to the NFVO, and might make sense only in very rare use cases.
    ...    Consequently, the VNFM may either allow creating a subscription resource if another subscription resource with the
    ...    same filter and callbackUri already exists (in which case it shall return the "201 Created" response code), or may decide
    ...    to not create a duplicate subscription resource (in which case it shall return a "303 See Other" response code referencing
    ...    the existing subscription resource with the same filter and callbackUri).
    Set headers    {"Content-Type": "${CONTENT_TYPE_JSON}"}
    Set headers    {"Accept": "${ACCEPT_JSON}"}
137
    Run Keyword If    ${AUTH_USAGE} == 1    Set Headers    {"${AUTHORIZATION_HEADER}":"${AUTHORIZATION_TOKEN}"}
138
139
140
141
142
143
144
145
146
    ${body}=    Get File    jsons/subscriptions.json
    ${body}=    Replace String    ${body}    \${callback_uri}    ${callback_uri}
    ${body}=    Replace String    ${body}    \${callback_port}    ${callback_port}
    ${body}=    Replace String    ${body}    \${callback_endpoint}    ${callback_endpoint}
    Log  Creating mock request and response to handle GET operation on notification endpoint
    &{notification_request}=  Create Mock Request Matcher	GET  ${callback_endpoint}
    &{notification_response}=  Create Mock Response	status_code=204
    Log    Issue the subscription request
    Create Mock Expectation  ${notification_request}  ${notification_response}
Elian Kraja's avatar
Elian Kraja committed
147
    Post    ${apiRoot}/${apiName}/${apiVersion}/subscriptions    ${body}    allow_redirects=false
148
149
150
151
152
	${output}=    Output    response
	Set Global Variable    ${response}    ${output}
	Clear Requests    ${callback_endpoint}
    #Run Keyword If    ${NFVO_CHECKS_NOTIF_ENDPOINT} == 1    #removed as the check of notif endpoint is done by NFVO while processing subscription reques
    #...    Check Notification Endpoint 
153
154
155
    


Giacomo Bernini's avatar
upd    
Giacomo Bernini committed
156
Send Put Request for VNF Performance Subscriptions
157
    [Documentation]    This method is not supported. When this method is requested on this resource, the VNFM shall return a "405 Method
Michele Carignani's avatar
Michele Carignani committed
158
    ...    Not Allowed" response as defined in Clause 6.4.7.3.3.
159
    Run Keyword If    ${AUTH_USAGE} == 1    Set Headers    {"${AUTHORIZATION_HEADER}":"${AUTHORIZATION_TOKEN}"}
160
161
162
163
164
165
    PUT    ${apiRoot}/${apiName}/${apiVersion}/subscriptions
    ${output}=    Output    response
    Set Suite Variable    ${response}    ${output}
    # Integer    response status    405
    # Log    Received 405 Method not implemented as expected

Giacomo Bernini's avatar
upd    
Giacomo Bernini committed
166
Send Patch Request for VNF Performance Subscriptions
167
    [Documentation]    This method is not supported. When this method is requested on this resource, the VNFM shall return a "405 Method
Michele Carignani's avatar
Michele Carignani committed
168
    ...    Not Allowed" response as defined in Clause 6.4.7.3.4.
169
    Run Keyword If    ${AUTH_USAGE} == 1    Set Headers    {"${AUTHORIZATION_HEADER}":"${AUTHORIZATION_TOKEN}"}
170
171
172
173
174
175
    PATCH    ${apiRoot}/${apiName}/${apiVersion}/subscriptions
    ${output}=    Output    response
    Set Suite Variable    ${response}    ${output}
    # Integer    response status    405
    # Log    Received 405 Method not implemented as expected

Giacomo Bernini's avatar
upd    
Giacomo Bernini committed
176
Send Delete Request for VNF Performance Subscriptions
177
    [Documentation]    This method is not supported. When this method is requested on this resource, the VNFM shall return a "405 Method
Michele Carignani's avatar
Michele Carignani committed
178
    ...    Not Allowed" response as defined in Clause 6.4.7.3.5.
179
    Run Keyword If    ${AUTH_USAGE} == 1    Set Headers    {"${AUTHORIZATION_HEADER}":"${AUTHORIZATION_TOKEN}"}
180
181
182
183
184
185
    DELETE    ${apiRoot}/${apiName}/${apiVersion}/subscriptions
    ${output}=    Output    response
    Set Suite Variable    ${response}    ${output}
    # Integer    response status    405
    # Log    Received 405 Method not implemented as expected

Giacomo Bernini's avatar
upd    
Giacomo Bernini committed
186
187
Get Individual VNF Performance Subscription
    Set headers    {"Accept": "${ACCEPT_JSON}"}
188
    Run Keyword If    ${AUTH_USAGE} == 1    Set Headers    {"${AUTHORIZATION_HEADER}":"${AUTHORIZATION_TOKEN}"}
Giacomo Bernini's avatar
upd    
Giacomo Bernini committed
189
190
191
192
193
194
    GET    ${apiRoot}/${apiName}/${apiVersion}/subscriptions/${subscriptionId}
    ${output}=    Output    response
    Set Suite Variable    ${response}    ${output}

GET individual VNF Performance Subscription with invalid resource identifier
    Set headers    {"Accept": "${ACCEPT_JSON}"}
195
    Run Keyword If    ${AUTH_USAGE} == 1    Set Headers    {"${AUTHORIZATION_HEADER}":"${AUTHORIZATION_TOKEN}"}
Giacomo Bernini's avatar
upd    
Giacomo Bernini committed
196
197
198
    GET    ${apiRoot}/${apiName}/${apiVersion}/subscriptions/${erroneousSubscriptionId}
    ${output}=    Output    response
    Set Suite Variable    ${response}    ${output}
199

Giacomo Bernini's avatar
upd    
Giacomo Bernini committed
200
201
Send Delete request for individual VNF Performance Subscription
    Set headers    {"Accept": "${ACCEPT_JSON}"}
202
    Run Keyword If    ${AUTH_USAGE} == 1    Set Headers    {"${AUTHORIZATION_HEADER}":"${AUTHORIZATION_TOKEN}"}
Giacomo Bernini's avatar
upd    
Giacomo Bernini committed
203
204
205
    DELETE    ${apiRoot}/${apiName}/${apiVersion}/subscriptions/${subscriptionId}
    ${output}=    Output    response
    Set Suite Variable    ${response}    ${output}
206

Giacomo Bernini's avatar
upd    
Giacomo Bernini committed
207
208
Send Delete request for individual VNF Performance Subscription with invalid resource identifier
    Log    Trying to delete a subscription in the VNFM with invalid id
209
    Run Keyword If    ${AUTH_USAGE} == 1    Set Headers    {"${AUTHORIZATION_HEADER}":"${AUTHORIZATION_TOKEN}"}
Giacomo Bernini's avatar
upd    
Giacomo Bernini committed
210
211
    DELETE    ${apiRoot}/${apiName}/${apiVersion}/subscriptions/${erroneousSubscriptionId}
    ${output}=    Output    response
212
    Set Suite Variable    ${response}    ${output}
Giacomo Bernini's avatar
upd    
Giacomo Bernini committed
213
214

Send Post request for individual VNF Performance Subscription
215
    Run Keyword If    ${AUTH_USAGE} == 1    Set Headers    {"${AUTHORIZATION_HEADER}":"${AUTHORIZATION_TOKEN}"}
Giacomo Bernini's avatar
upd    
Giacomo Bernini committed
216
217
    POST    ${apiRoot}/${apiName}/${apiVersion}/subscriptions/${newSubscriptionId}
    ${output}=    Output    response
218
    Set Suite Variable    ${response}    ${output}
Giacomo Bernini's avatar
upd    
Giacomo Bernini committed
219
220

Send Put request for individual VNF Performance Threshold
221
    Run Keyword If    ${AUTH_USAGE} == 1    Set Headers    {"${AUTHORIZATION_HEADER}":"${AUTHORIZATION_TOKEN}"}
Giacomo Bernini's avatar
upd    
Giacomo Bernini committed
222
223
224
225
226
    GET    ${apiRoot}/${apiName}/${apiVersion}/subscriptions/${subscriptionId}
    ${origOutput}=    Output    response
    Set Suite Variable    ${origResponse}    ${origOutput}
    PUT    ${apiRoot}/${apiName}/${apiVersion}/subscriptions/${subscriptionId}
    ${output}=    Output    response
227
    Set Suite Variable    ${response}    ${output}
Giacomo Bernini's avatar
upd    
Giacomo Bernini committed
228
229
    
Send Patch request for individual VNF Performance Threshold
230
    Run Keyword If    ${AUTH_USAGE} == 1    Set Headers    {"${AUTHORIZATION_HEADER}":"${AUTHORIZATION_TOKEN}"}
Giacomo Bernini's avatar
upd    
Giacomo Bernini committed
231
232
233
234
235
    GET    ${apiRoot}/${apiName}/${apiVersion}/subscriptions/${subscriptionId}
    ${origOutput}=    Output    response
    Set Suite Variable    ${origResponse}    ${origOutput}
    PATCH    ${apiRoot}/${apiName}/${apiVersion}/subscriptions/${subscriptionId}
    ${output}=    Output    response
236
    Set Suite Variable    ${response}    ${output}
Giacomo Bernini's avatar
upd    
Giacomo Bernini committed
237
238
239
240
241
242

Check Postcondition VNF Performance Subscription is Unmodified (Implicit)
    Log    Check postconidtion subscription not modified
    GET individual VNF Performance Subscription
    Log    Check Response matches original VNF Threshold
    ${subscription}=    evaluate    json.loads('''${response['body']}''')    json
243
244
    Should Be Equal As Strings    ${origResponse['body']['id']}    ${subscription.id}
    Should Be Equal As Strings    ${origResponse['body']['callbackUri']}    ${subscription.callbackUri}
Giacomo Bernini's avatar
upd    
Giacomo Bernini committed
245
246
247
248

Check Postcondition VNF Performance Subscription is not Created
    Log    Trying to get a new subscription
    Set Headers    {"Accept": "${ACCEPT_JSON}"}
249
    Run Keyword If    ${AUTH_USAGE} == 1    Set Headers    {"${AUTHORIZATION_HEADER}":"${AUTHORIZATION_TOKEN}"}
Giacomo Bernini's avatar
upd    
Giacomo Bernini committed
250
251
    GET    ${apiRoot}/${apiName}/${apiVersion}/subscriptions/${newSubscriptionId}
    ${output}=    Output    response
252
    Set Suite Variable    ${response}    ${output}
Giacomo Bernini's avatar
upd    
Giacomo Bernini committed
253
254
255
256
257
258
259
260
261
    Check HTTP Response Status Code Is    404 

Check Postcondition VNF Performance Subscription is Deleted
    Log    Check Postcondition Subscription is deleted
    GET individual VNF Performance Subscription
    Check HTTP Response Status Code Is    404 

Check HTTP Response Body Subscription Identifier matches the requested Subscription
    Log    Trying to check response ID
262
    Should Be Equal As Strings   ${response['body']['id']}    ${subscriptionId} 
Giacomo Bernini's avatar
upd    
Giacomo Bernini committed
263
264
    Log    Subscription identifier as expected
    
265
266
Check HTTP Response Status Code Is
    [Arguments]    ${expected_status}    
267
    Should Be Equal As Strings    ${response['status']}    ${expected_status}
268
269
270
271
272
273
    Log    Status code validated 
    
    
    
Check HTTP Response Body Json Schema Is
    [Arguments]    ${input}
274
275
    Run Keyword If    '${input}' == 'ProblemDetails'    Should Contain    ${response['headers']['Content-Type']}    application/problem+json
    ...    ELSE    Should Contain    ${response['headers']['Content-Type']}    application/json
276
    ${schema} =    Catenate    SEPARATOR=    ${input}    .schema.json
277
278
279
280
    Validate Json    ${schema}    ${response['body']}
    Log    Json Schema Validation OK  


Giacomo Bernini's avatar
upd    
Giacomo Bernini committed
281
Check HTTP Response Body Is Empty
282
283
284
285
286
287
    Should Be Empty    ${response['body']}    
    Log    No json schema is provided. Validation OK  


Check HTTP Response Body Subscriptions Match the requested Attribute-Based Filter
    Log    Check Response includes VNF Performance Management according to filter
288
    Should Be Equal As Strings    ${response['body']['callbackUri']}    ${callbackUri_Sub}
289

290
Check HTTP Response Body PmSubscription Attributes Values Match the Issued Subscription
291
292
293
    Log    Check Response matches subscription
    ${body}=    Get File    jsons/subscriptions.json
    ${subscription}=    evaluate    json.loads('''${body}''')    json
294
    Should Be Equal As Strings    ${response['body']['callbackUri']}    ${subscription['callbackUri']}
295

Giacomo Bernini's avatar
upd    
Giacomo Bernini committed
296
Check Postcondition VNF Performance Subscription Is Set
297
298
    Log    Check Postcondition subscription exist
    Set Headers    {"Accept": "${ACCEPT_JSON}"}
299
    Run Keyword If    ${AUTH_USAGE} == 1    Set Headers    {"${AUTHORIZATION_HEADER}":"${AUTHORIZATION_TOKEN}"}
300
301
302
303
    GET    ${apiRoot}/${apiName}/${apiVersion}/subscriptions/${response['body']['id']}
    ${output}=    Output    response
    Set Suite Variable    ${response}    ${output}
    Check HTTP Response Status Code Is    200
Giacomo Bernini's avatar
Giacomo Bernini committed
304

305
Check Postcondition Subscription Resource Returned in Location Header Is Available
Giacomo Bernini's avatar
Giacomo Bernini committed
306
    Log    Going to check postcondition
307
    Run Keyword If    ${AUTH_USAGE} == 1    Set Headers    {"${AUTHORIZATION_HEADER}":"${AUTHORIZATION_TOKEN}"}
308
    GET    ${response['headers']['Location']}
Giacomo Bernini's avatar
Giacomo Bernini committed
309
310
311
312
313
314
315
316
    Integer    response status    200
    Log    Received a 200 OK as expected
    ${contentType}=    Output    response headers Content-Type
    Should Contain    ${contentType}    application/json
    ${result}=    Output    response body
    Validate Json    PmSubscription.schema.json    ${result}
    Log    Validated PmSubscription schema
 
Giacomo Bernini's avatar
upd    
Giacomo Bernini committed
317
318
319
Check Postcondition VNF Performance Subscriptions Exists
    Log    Checking that subscriptions exists
    Get all VNF Performance Subscriptions         
320
321
322

Check HTTP Response Header Contains
    [Arguments]    ${CONTENT_TYPE}
323
    Should Contain    ${response['headers']}    ${CONTENT_TYPE}
324
    Log    Header is present
325

Giacomo Bernini's avatar
upd    
Giacomo Bernini committed
326
327
Check HTTP Response Location Header Resource URI
    Log    Going to check
328
    GET    ${response['headers']['Location']}
Giacomo Bernini's avatar
upd    
Giacomo Bernini committed
329
330
331
332
333
334
335
    Integer    response status    200
    Log    Received a 200 OK as expected
    ${contentType}=    Output    response headers Content-Type
    Should Contain    ${contentType}    application/json
    ${result}=    Output    response body
    Validate Json    PmSubscription.schema.json    ${result}
    Log    Validated PmSubscription schema
336
337

Create Sessions
338
    Pass Execution If    ${VNFM_CHECKS_NOTIF_ENDPOINT} == 0   MockServer not necessary to run    
339
340
341
342
343
344
    Start Process  java  -jar  ${MOCK_SERVER_JAR}    -serverPort  ${callback_port}  alias=mockInstance
    Wait For Process  handle=mockInstance  timeout=5s  on_timeout=continue
    Create Mock Session  ${callback_uri}:${callback_port}
    
Check Notification Endpoint
    &{notification_request}=  Create Mock Request Matcher	GET  ${callback_endpoint}    
345
346
    &{headers} =    Create Dictionary    Content-Type=application/json
    &{notification_response}=  Create Mock Response    headers=${headers}    status_code=204
347
348
349
    Create Mock Expectation  ${notification_request}  ${notification_response}
    Wait Until Keyword Succeeds    ${total_polling_time}   ${polling_interval}   Verify Mock Expectation    ${notification_request}
    Clear Requests  ${callback_endpoint}
350
Check LINK in Header
351
    ${linkURL}=    Get Value From Json    ${response['headers']}    $..Link
352
    Should Not Be Empty    ${linkURL}