From 50e2b0b4bb978116306c5b935ca851371bd13630 Mon Sep 17 00:00:00 2001
From: Elian Kraja <e.kraja@nextworks.it>
Date: Mon, 5 Nov 2018 17:10:13 +0100
Subject: [PATCH] Adding initial work on Performance Management

---
 .../IndividualPmJob.robot                     |  76 +++++++
 .../IndividualReport.robot                    |  75 +++++++
 .../PMJobs.robot                              | 201 ++++++++++++++++++
 .../environment/IndividualPmJob.txt           |   3 +
 .../environment/generic.txt                   |  19 ++
 .../environment/individualSubscription.txt    |   3 +
 .../environment/individualThresholds.txt      |   3 +
 .../environment/pmJobs.txt                    |   4 +
 .../environment/reports.txt                   |   4 +
 .../environment/subscriptions.txt             |   3 +
 .../environment/thresholds.txt                |   3 +
 .../jsons/CreatePmJobRequest.json             |  10 +
 .../jsons/CreateThresholdRequest.json         |  12 ++
 .../jsons/subscriptions.json                  |   6 +
 .../schemas/PerformanceReport.schema.json     |   1 +
 .../schemas/PmJob.schema.json                 |   1 +
 .../schemas/PmSubscriptions.schema.json       |   1 +
 .../schemas/ProblemDetails.schema.json        |   1 +
 .../schemas/Subscriptions.schema.json         |   1 +
 .../schemas/Threshold.schema.json             |   1 +
 .../schemas/criteria.schema.json              |  34 +++
 .../schemas/links.schema.json                 |  35 +++
 .../schemas/reports.schema.json               |  26 +++
 TrackingStatus.txt                            |   8 +-
 24 files changed, 527 insertions(+), 4 deletions(-)
 create mode 100644 SOL002/VNFPerformanceManagement-API_nxw/IndividualPmJob.robot
 create mode 100644 SOL002/VNFPerformanceManagement-API_nxw/IndividualReport.robot
 create mode 100644 SOL002/VNFPerformanceManagement-API_nxw/PMJobs.robot
 create mode 100644 SOL002/VNFPerformanceManagement-API_nxw/environment/IndividualPmJob.txt
 create mode 100644 SOL002/VNFPerformanceManagement-API_nxw/environment/generic.txt
 create mode 100644 SOL002/VNFPerformanceManagement-API_nxw/environment/individualSubscription.txt
 create mode 100644 SOL002/VNFPerformanceManagement-API_nxw/environment/individualThresholds.txt
 create mode 100644 SOL002/VNFPerformanceManagement-API_nxw/environment/pmJobs.txt
 create mode 100644 SOL002/VNFPerformanceManagement-API_nxw/environment/reports.txt
 create mode 100644 SOL002/VNFPerformanceManagement-API_nxw/environment/subscriptions.txt
 create mode 100644 SOL002/VNFPerformanceManagement-API_nxw/environment/thresholds.txt
 create mode 100644 SOL002/VNFPerformanceManagement-API_nxw/jsons/CreatePmJobRequest.json
 create mode 100644 SOL002/VNFPerformanceManagement-API_nxw/jsons/CreateThresholdRequest.json
 create mode 100644 SOL002/VNFPerformanceManagement-API_nxw/jsons/subscriptions.json
 create mode 100644 SOL002/VNFPerformanceManagement-API_nxw/schemas/PerformanceReport.schema.json
 create mode 100644 SOL002/VNFPerformanceManagement-API_nxw/schemas/PmJob.schema.json
 create mode 100644 SOL002/VNFPerformanceManagement-API_nxw/schemas/PmSubscriptions.schema.json
 create mode 100644 SOL002/VNFPerformanceManagement-API_nxw/schemas/ProblemDetails.schema.json
 create mode 100644 SOL002/VNFPerformanceManagement-API_nxw/schemas/Subscriptions.schema.json
 create mode 100644 SOL002/VNFPerformanceManagement-API_nxw/schemas/Threshold.schema.json
 create mode 100644 SOL002/VNFPerformanceManagement-API_nxw/schemas/criteria.schema.json
 create mode 100644 SOL002/VNFPerformanceManagement-API_nxw/schemas/links.schema.json
 create mode 100644 SOL002/VNFPerformanceManagement-API_nxw/schemas/reports.schema.json

diff --git a/SOL002/VNFPerformanceManagement-API_nxw/IndividualPmJob.robot b/SOL002/VNFPerformanceManagement-API_nxw/IndividualPmJob.robot
new file mode 100644
index 00000000..c876be05
--- /dev/null
+++ b/SOL002/VNFPerformanceManagement-API_nxw/IndividualPmJob.robot
@@ -0,0 +1,76 @@
+*** Settings ***
+Library           JSONSchemaLibrary    schemas/
+Resource          environment/generic.txt    # Generic Parameters
+Library           JSONLibrary
+Resource          environment/IndividualPmJob.txt
+Library           REST    ${VNFM_SCHEMA}://${VNFM_HOST}:${VNFM_PORT}
+
+*** Test Cases ***
+GET Individual PM Job
+    Log    Trying to get a Pm Job present in the NFVO Catalogue
+    Set Headers    {"Accept": "${ACCEPT_JSON}"}
+    Run Keyword If    ${VNFM_AUTH_USAGE} == 1    Set Headers    {"Authorization": "${VNFM_AUTHENTICATION}"}
+    GET    ${apiRoot}/${apiName}/${apiVersion}/pm_jobs/${pmJobId}
+    Integer    response status    200
+    ${contentType}=    Output    response headers Content-Type
+    Should Contain    ${contentType}    ${CONTENT_TYPE_JSON}
+    Log    Trying to validate response
+    ${result}=    Output    response body
+    ${json}=    evaluate    json.loads('''${result}''')    json
+    Validate Json    PmJob.schema.json    ${json}
+    Log    Validation OK
+
+GET Individual PM Job - Negative (Not Found)
+    Log    Trying to perform a negative get, using erroneous PM Job identifier
+    Set Headers    {"Accept": "${ACCEPT_JSON}"}
+    Run Keyword If    ${VNFM_AUTH_USAGE} == 1    Set Headers    {"Authorization": "${VNFM_AUTHENTICATION}"}
+    GET    ${apiRoot}/${apiName}/${apiVersion}/pm_jobs/${erroneousPmJobId}
+    Integer    response status    404
+    Log    Received 404 Not Found as expected
+    ${contentType}=    Output    response headers Content-Type
+    Should Contain    ${contentType}    ${CONTENT_TYPE_JSON}
+    Log    Trying to validate ProblemDetails
+    ${problemDetails}=    Output    response body
+    ${json}=    evaluate    json.loads('''${problemDetails}''')    json
+    Validate Json    ProblemDetails.schema.json    ${json}
+    Log    Validation OK
+
+DELETE Individual PM Job
+    Log    Trying to delete an existing PM Job
+    Set Headers    {"Accept": "${ACCEPT_JSON}"}
+    Run Keyword If    ${VNFM_AUTH_USAGE} == 1    Set Headers    {"Authorization": "${VNFM_AUTHENTICATION}"}
+    DELETE    ${apiRoot}/${apiName}/${apiVersion}/pm_jobs/${pmJobId}
+    Integer    response status    204
+    Log    Received 204 No Content as expected
+
+DELETE Individual PM Job - Negative (Not Found)
+    Log    Trying to delete an existing PM Job
+    Set Headers    {"Accept": "${ACCEPT_JSON}"}
+    Run Keyword If    ${VNFM_AUTH_USAGE} == 1    Set Headers    {"Authorization": "${VNFM_AUTHENTICATION}"}
+    DELETE    ${apiRoot}/${apiName}/${apiVersion}/pm_jobs/${erroneousPmJobId}
+    Integer    response status    404
+    Log    Received 204 No Content as expected
+
+POST Individual PM Job - (Method not implemented)
+    Log    Trying to perform a POST (method should not be implemented)
+    Set Headers    {"Accept": "${ACCEPT_JSON}"}
+    Run Keyword If    ${VNFM_AUTH_USAGE} == 1    Set Headers    {"Authorization": "${VNFM_AUTHENTICATION}"}
+    POST    ${apiRoot}/${apiName}/${apiVersion}/pm_jobs/${pmJobId}
+    Integer    response status    405
+    Log    Received 405 Method not implemented as expected
+
+PUT Individual PM Job - (Method not implemented)
+    Log    Trying to perform a PUT. This method should not be implemented
+    Set Headers    {"Accept": "${ACCEPT_JSON}"}
+    Run Keyword If    ${VNFM_AUTH_USAGE} == 1    Set Headers    {"Authorization": "${VNFM_AUTHENTICATION}"}
+    PUT    ${apiRoot}/${apiName}/${apiVersion}/pm_jobs/${pmJobId}
+    Integer    response status    405
+    Log    Received 405 Method not implemented as expected
+
+PATCH Individual PM Job - (Method not implemented)
+    Log    Trying to perform a PATCH. This method should not be implemented
+    Set Headers    {"Accept": "${ACCEPT_JSON}"}
+    Run Keyword If    ${VNFM_AUTH_USAGE} == 1    Set Headers    {"Authorization": "${VNFM_AUTHENTICATION}"}
+    PATCH    ${apiRoot}/${apiName}/${apiVersion}/pm_jobs/${pmJobId}
+    Integer    response status    405
+    Log    Received 405 Method not implemented as expected
diff --git a/SOL002/VNFPerformanceManagement-API_nxw/IndividualReport.robot b/SOL002/VNFPerformanceManagement-API_nxw/IndividualReport.robot
new file mode 100644
index 00000000..4bb2b371
--- /dev/null
+++ b/SOL002/VNFPerformanceManagement-API_nxw/IndividualReport.robot
@@ -0,0 +1,75 @@
+*** Settings ***
+Documentation     This resource represents an individual performance report that was collected by a PM job. The client can use this
+...               resource to read the performance report. The URI of this report can be obtained from a
+...               PerformanceInformationAvailableNotification (see clause 6.5.2.5) or from the representation of the "Individual PM job"
+...               resource.
+...               It is determined by means outside the scope of the present document, such as configuration or policy, how long an
+...               individual performance report is available.
+Library           JSONSchemaLibrary    schemas/
+Resource          environment/generic.txt    # Generic Parameters
+Resource          environment/reports.txt
+Library           JSONLibrary
+Library           REST    ${VNFM_SCHEMA}://${VNFM_HOST}:${VNFM_PORT}
+
+*** Test Cases ***
+GET Report on Single PM Job
+    [Documentation]    The client can use this method for reading an individual performance report.
+    ...    This method shall follow the provisions specified in the tables 6.4.4.3.2-1 and 6.4.4.3.2-2 for URI query parameters,
+    ...    request and response data structures, and response codes.
+    Set Headers    {"Accept": "${ACCEPT_JSON}"}
+    Run Keyword If    ${VNFM_AUTH_USAGE} == 1    Set Headers    {"Authorization": ${VNFM_AUTHENTICATION}"}
+    GET    ${apiRoot}/${apiName}/${apiVersion}/pm_jobs/${pmJobId}/reports/${reportId}
+    Integer    response status    200
+    ${contentType}=    Output    response headers Content-Type
+    Should Contain    ${contentType}    ${CONTENT_TYPE_JSON}
+    Log    Trying to validate result with PerformanceReport schema
+    ${result}=    Output    response body
+    ${json}=    evaluate    json.loads('''${result}''')    json
+    Validate Json    PerformanceReport.schema.json    ${json}
+
+GET Report on Single PM Job - Negative (Not Found)
+    [Documentation]    The client can use this method for reading an individual performance report.
+    ...    This method shall follow the provisions specified in the tables 6.4.4.3.2-1 and 6.4.4.3.2-2 for URI query parameters,
+    ...    request and response data structures, and response codes.
+    Set Headers    {"Accept": "${ACCEPT_JSON}"}
+    Run Keyword If    ${VNFM_AUTH_USAGE} == 1    Set Headers    {"Authorization": ${VNFM_AUTHENTICATION}"}
+    GET    ${apiRoot}/${apiName}/${apiVersion}/pm_jobs/${pmJobId}/reports/${erroneousReportId}
+    Integer    response status    404
+    Log    Received 404 Not Found as expected
+    Log    Trying to validate ProblemDetails
+    ${problemDetails}=    Output    response body
+    ${json}=    evaluate    json.loads('''${problemDetails}''')    json
+    Validate Json    ProblemDetails.schema.json    ${json}
+    Log    Validation OK
+
+POST Reports - (Method not implemented)
+    [Documentation]    This method is not supported. When this method is requested on this resource, the VNFM shall return a "405 Method
+    ...    Not Allowed" response as defined in clause 4.3.5.4.
+    Run Keyword If    ${VNFM_AUTH_USAGE} == 1    Set Headers    {"Authorization": "${VNFM_AUTHENTICATION}"}
+    POST    ${apiRoot}/${apiName}/${apiVersion}/pm_jobs/${pmJobId}/reports/${reportId}
+    Integer    response status    405
+    Log    Received 405 Method not implemented as expected
+
+PUT Reports - (Method not implemented)
+    [Documentation]    This method is not supported. When this method is requested on this resource, the VNFM shall return a "405 Method
+    ...    Not Allowed" response as defined in clause 4.3.5.4.
+    Run Keyword If    ${VNFM_AUTH_USAGE} == 1    Set Headers    {"Authorization": "${VNFM_AUTHENTICATION}"}
+    PUT    ${apiRoot}/${apiName}/${apiVersion}/pm_jobs/${pmJobId}/reports/${reportId}
+    Integer    response status    405
+    Log    Received 405 Method not implemented as expected
+
+PATCH Reports - (Method not implemented)
+    [Documentation]    This method is not supported. When this method is requested on this resource, the VNFM shall return a "405 Method
+    ...    Not Allowed" response as defined in clause 4.3.5.4.
+    Run Keyword If    ${VNFM_AUTH_USAGE} == 1    Set Headers    {"Authorization": "${VNFM_AUTHENTICATION}"}
+    PATCH    ${apiRoot}/${apiName}/${apiVersion}/pm_jobs/${pmJobId}/reports/${reportId}
+    Integer    response status    405
+    Log    Received 405 Method not implemented as expected
+
+DELETE Reports - (Method not implemented)
+    [Documentation]    This method is not supported. When this method is requested on this resource, the VNFM shall return a "405 Method
+    ...    Not Allowed" response as defined in clause 4.3.5.4.
+    Run Keyword If    ${VNFM_AUTH_USAGE} == 1    Set Headers    {"Authorization": "${VNFM_AUTHENTICATION}"}
+    DELETE    ${apiRoot}/${apiName}/${apiVersion}/pm_jobs/${pmJobId}/reports/${reportId}
+    Integer    response status    405
+    Log    Received 405 Method not implemented as expected
diff --git a/SOL002/VNFPerformanceManagement-API_nxw/PMJobs.robot b/SOL002/VNFPerformanceManagement-API_nxw/PMJobs.robot
new file mode 100644
index 00000000..df214f4c
--- /dev/null
+++ b/SOL002/VNFPerformanceManagement-API_nxw/PMJobs.robot
@@ -0,0 +1,201 @@
+*** Settings ***
+Library           JSONSchemaLibrary    schemas/
+Resource          environment/generic.txt    # Generic Parameters
+Library           JSONLibrary
+Library           OperatingSystem
+Resource          environment/pmJobs.txt
+Library           REST    ${VNFM_SCHEMA}://${VNFM_HOST}:${VNFM_PORT}
+
+*** Test Cases ***
+GET all Pm Jobs
+    Log    Trying to get all PM Jobs present in the VNFM
+    Set Headers    {"Accept": "${ACCEPT_JSON}"}
+    Run Keyword If    ${VNFM_AUTH_USAGE} == 1    Set Headers    {"Authorization": "${VNFM_AUTHENTICATION}"}
+    GET    ${apiRoot}/${apiName}/${apiVersion}/pm_jobs
+    Integer    response status    200
+    ${contentType}=    Output    response headers Content-Type
+    Should Contain    ${contentType}    ${CONTENT_TYPE_JSON}
+    Log    Trying to validate response
+    ${result}=    Output    response body
+    ${json}=    evaluate    json.loads('''${result}''')    json
+    Validate Json    PmJob.schema.json    ${json}
+    Log    Validation OK
+    Log    Checking that reports element is missing
+    ${reports}=    Get Value From Json    ${json}    $..reports
+    Should Be Empty    ${reports}
+    Log    Reports element is empty as expected
+
+GET all Pm Jobs - Filter
+    Log    Trying to get all PM Jobs present in the VNFM, using filter params
+    Set Headers    {"Accept": "${ACCEPT_JSON}"}
+    Run Keyword If    ${VNFM_AUTH_USAGE} == 1    Set Headers    {"Authorization": "${VNFM_AUTHENTICATION}"}
+    GET    ${apiRoot}/${apiName}/${apiVersion}/pm_jobs?${POS_FILTER}
+    Integer    response status    200
+    ${contentType}=    Output    response headers Content-Type
+    Should Contain    ${contentType}    ${CONTENT_TYPE_JSON}
+    Log    Trying to validate response
+    ${result}=    Output    response body
+    ${json}=    evaluate    json.loads('''${result}''')    json
+    Validate Json    PmJob.schema.json    ${json}
+    Log    Validation OK
+
+GET all Pm Jobs - all_fields
+    Log    Trying to get all PM Jobs present in the VNFM, using 'all_fields' filter
+    Set Headers    {"Accept": "${ACCEPT_JSON}"}
+    Run Keyword If    ${VNFM_AUTH_USAGE} == 1    Set Headers    {"Authorization": "${VNFM_AUTHENTICATION}"}
+    GET    ${apiRoot}/${apiName}/${apiVersion}/pm_jobs?all_fields
+    Integer    response status    200
+    ${contentType}=    Output    response headers Content-Type
+    Should Contain    ${contentType}    ${CONTENT_TYPE_JSON}
+    Log    Trying to validate response
+    ${result}=    Output    response body
+    ${json}=    evaluate    json.loads('''${result}''')    json
+    Validate Json    PmJob.schema.json    ${json}
+    Log    Validation OK
+    Log    Trying to validate criteria schema
+    ${criteria}=    Get Value From Json    ${json}    $..criteria
+    Validate Json    criteria.schema.json    ${criteria[0]}
+    Log    Validation for criteria schema OK
+    Log    Trying to validate criteria schema
+    ${reports}=    Get Value From Json    ${json}    $..reports
+    Validate Json    reports.schema.json    ${reports[0]}
+    Log    Validation for reports schema OK
+    Log    Validating _links schema
+    ${links}=    Get Value From Json    ${json}    $.._links
+    Validate Json    links.schema.json    ${links[0]}
+    Log    Validation for _links schema OK
+
+GET all Pm Jobs - exclude_default
+    Log    Trying to get all VNF Packages present in the VNFM, using filter params
+    Set Headers    {"Accept": "${ACCEPT_JSON}"}
+    Run Keyword If    ${VNFM_AUTH_USAGE} == 1    Set Headers    {"Authorization": "${VNFM_AUTHENTICATION}"}
+    GET    ${apiRoot}/${apiName}/${apiVersion}/pm_jobs?exclude_default
+    Integer    response status    200
+    ${contentType}=    Output    response headers Content-Type
+    Should Contain    ${contentType}    ${CONTENT_TYPE_JSON}
+    Log    Trying to validate response
+    ${result}=    Output    response body
+    ${json}=    evaluate    json.loads('''${result}''')    json
+    Validate Json    PmJob.schema.json    ${json}
+    Log    Validation OK
+    Log    Checking that reports element is missing
+    ${reports}=    Get Value From Json    ${json}    $..reports
+    Should Be Empty    ${reports}
+    Log    Reports element is empty as expected
+
+GET all Pm Jobs - fields
+    Log    Trying to get all VNF Packages present in the VNFM, using filter params
+    Pass Execution If    ${FIELDS_USAGE} == 0    Skipping test as VNFM is not supporting 'fields'
+    Set Headers    {"Accept": "${ACCEPT_JSON}"}
+    Run Keyword If    ${VNFM_AUTH_USAGE} == 1    Set Headers    {"Authorization": "${VNFM_AUTHENTICATION}"}
+    GET    ${apiRoot}/${apiName}/${apiVersion}/pm_jobs?fields=${fields}
+    Integer    response status    200
+    ${contentType}=    Output    response headers Content-Type
+    Should Contain    ${contentType}    ${CONTENT_TYPE_JSON}
+    Log    Trying to validate response
+    ${result}=    Output    response body
+    ${json}=    evaluate    json.loads('''${result}''')    json
+    Validate Json    PmJob.schema.json    ${json}
+    Log    Validation OK
+    Log    Trying to validate criteria schema
+    ${criteria}=    Get Value From Json    ${json}    $..criteria
+    Validate Json    criteria.schema.json    ${criteria[0]}
+    Log    Validation for criteria schema OK
+    Log    Trying to validate criteria schema
+    ${reports}=    Get Value From Json    ${json}    $..reports
+    Validate Json    reports.schema.json    ${reports[0]}
+    Log    Validation for reports schema OK
+
+GET all Pm Jobs - exclude_fields
+    Log    Trying to get all VNF Packages present in the VNFM, using filter params
+    Pass Execution If    ${FIELDS_USAGE} == 0    Skipping test as VNFM is not supporting 'fields'
+    Set Headers    {"Accept": "${ACCEPT_JSON}"}
+    Run Keyword If    ${VNFM_AUTH_USAGE} == 1    Set Headers    {"Authorization": "${VNFM_AUTHENTICATION}"}
+    GET    ${apiRoot}/${apiName}/${apiVersion}/pm_jobs?fields=${fields}
+    Integer    response status    200
+    ${contentType}=    Output    response headers Content-Type
+    Should Contain    ${contentType}    ${CONTENT_TYPE_JSON}
+    Log    Trying to validate response
+    ${result}=    Output    response body
+    ${json}=    evaluate    json.loads('''${result}''')    json
+    Validate Json    PmJob.schema.json    ${json}
+    Log    Validation OK
+    Log    Checking that reports element is missing
+    ${reports}=    Get Value From Json    ${json}    $..reports
+    Should Be Empty    ${reports}
+    Log    Reports element is empty as expected
+    Log    Checking that criteria element is missing
+    ${criteria}=    Get Value From Json    ${json}    $..criteria
+    Should Be Empty    ${criteria}
+    Log    Criteria element is empty as expected
+
+GET all Pm Jobs - Negative (wronge filter name)
+    Log    Trying to get all PM Jobs present in the VNFM, using an erroneous filter param
+    Set Headers    {"Accept": "${ACCEPT_JSON}"}
+    Run Keyword If    ${VNFM_AUTH_USAGE} == 1    Set Headers    {"Authorization": "${VNFM_AUTHENTICATION}"}
+    GET    ${apiRoot}/${apiName}/${apiVersion}/pm_jobs?${NEG_FILTER}
+    Integer    response status    400
+    Log    Received 400 Bad Request as expected
+    ${contentType}=    Output    response headers Content-Type
+    Should Contain    ${contentType}    ${CONTENT_TYPE_JSON}
+    Log    Trying to validate ProblemDetails
+    ${problemDetails}=    Output    response headers Content-Type
+    ${json}=    evaluate    json.loads('''${problemDetails}''')    json
+    Validate Json    ProblemDetails.schema.json    ${json}
+    Log    Validation OK
+
+GET all Pm Jobs (Negative: Not found)
+    Log    Trying to perform a GET on a erroneous URI
+    Set Headers    {"Accept": "${ACCEPT_JSON}"}
+    Run Keyword If    ${VNFM_AUTH_USAGE} == 1    Set Headers    {"Authorization": "${VNFM_AUTHENTICATION}"}
+    GET    ${apiRoot}/${apiName}/${apiVersion}/pm_job    # wrong URI /pm_job instead of /pm_jobs
+    Integer    response status    404
+    Log    Received 404 Not Found as expected
+    ${contentType}=    Output    response headers Content-Type
+    Should Contain    ${contentType}    ${CONTENT_TYPE_JSON}
+    Log    Trying to validate ProblemDetails
+    ${problemDetails}=    Output    response headers Content-Type
+    ${json}=    evaluate    json.loads('''${problemDetails}''')    json
+    Validate Json    ProblemDetails.schema.json    ${json}
+    Log    Validation OK
+
+POST all PM Jobs - Create new PM Job
+    Log    Creating a new PM Job
+    Set Headers    {"Accept": "${ACCEPT_JSON}"}
+    Set Headers    {"Content-Type": "${CONTENT_TYPE_JSON}"}
+    Run Keyword If    ${VNFM_AUTH_USAGE} == 1    Set Headers    {"Authorization": "${VNFM_AUTHENTICATION}"}
+    ${body}=    Get File    jsons/CreatePmJobRequest.json
+    POST    ${apiRoot}/${apiName}/${apiVersion}/pm_jobs    ${body}
+    Integer    response status    201
+    Log    Received 201 Created as expected
+    ${contentType}=    Output    response headers Content-Type
+    Should Contain    ${contentType}    ${CONTENT_TYPE_JSON}
+    Log    Trying to validate response
+    ${result}=    Output    response body
+    ${json}=    evaluate    json.loads('''${result}''')    json
+    Validate Json    PmJob.schema.json    ${json}
+    Log    Validation OK
+
+PUT all PM Jobs - (Method not implemented)
+    Log    Trying to perform a PUT. This method should not be implemented
+    Set Headers    {"Accept": "${ACCEPT_JSON}"}
+    Run Keyword If    ${VNFM_AUTH_USAGE} == 1    Set Headers    {"Authorization": "${VNFM_AUTHENTICATION}"}
+    PUT    ${apiRoot}/${apiName}/${apiVersion}/pm_jobs
+    Integer    response status    405
+    Log    Received 405 Method not implemented as expected
+
+PATCH all Pm Jobs - (Method not implemented)
+    Log    Trying to perform a PATCH. This method should not be implemented
+    Set Headers    {"Accept": "${ACCEPT_JSON}"}
+    Run Keyword If    ${VNFM_AUTH_USAGE} == 1    Set Headers    {"Authorization": "${VNFM_AUTHENTICATION}"}
+    PATCH    ${apiRoot}/${apiName}/${apiVersion}/pm_jobs
+    Integer    response status    405
+    Log    Received 405 Method not implemented as expected
+
+DELETE all Pm Jobs - (Method not implemented)
+    Log    Trying to perform a DELETE. This method should not be implemented
+    Set Headers    {"Accept": "${ACCEPT_JSON}"}
+    Run Keyword If    ${VNFM_AUTH_USAGE} == 1    Set Headers    {"Authorization": "${VNFM_AUTHENTICATION}"}
+    DELETE    ${apiRoot}/${apiName}/${apiVersion}/pm_jobs
+    Integer    response status    405
+    Log    Received 405 Method not implemented as expected
diff --git a/SOL002/VNFPerformanceManagement-API_nxw/environment/IndividualPmJob.txt b/SOL002/VNFPerformanceManagement-API_nxw/environment/IndividualPmJob.txt
new file mode 100644
index 00000000..a7823e6b
--- /dev/null
+++ b/SOL002/VNFPerformanceManagement-API_nxw/environment/IndividualPmJob.txt
@@ -0,0 +1,3 @@
+*** Variables ***
+${pmJobId}        29f4ff6a-be91-4ec8-856e-fcf1e2479e4e
+${erroneousPmJobId}    erroneousPmJobId
diff --git a/SOL002/VNFPerformanceManagement-API_nxw/environment/generic.txt b/SOL002/VNFPerformanceManagement-API_nxw/environment/generic.txt
new file mode 100644
index 00000000..4f4b0194
--- /dev/null
+++ b/SOL002/VNFPerformanceManagement-API_nxw/environment/generic.txt
@@ -0,0 +1,19 @@
+*** Variables ***
+${VNFM_HOST}      localhost    # Hostname of the VNFM
+${VNFM_PORT}      8080    # Listening port of the VNFM
+${NFVO_HOST}      localhost    # Hostname of the NFVO
+${NFVO_PORT}      8081    # Listening port of the NFVO
+${VNFM_SCHEMA}    https
+${NFVO_SCHEMA}    https
+${AUTHORIZATION}    Bearer 0b79bab50daca910b000d4f1a2b675d604257e42
+${CONTENT_TYPE_JSON}    application/json
+${ACCEPT_JSON}    application/json
+${apiRoot}        /
+${AUTH_USAGE}     1
+${NEG_AUTHORIZATION}    Bearer negativetoken
+${apiVersion}     v1
+${apiName}        vnfpm
+${FIELD_USAGE}    1
+${VNFM_AUTHENTICATION}    Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
+${VNFM_AUTH_USAGE}    1
+${VNFM_DUPLICATION}    1
diff --git a/SOL002/VNFPerformanceManagement-API_nxw/environment/individualSubscription.txt b/SOL002/VNFPerformanceManagement-API_nxw/environment/individualSubscription.txt
new file mode 100644
index 00000000..f5aa4ba9
--- /dev/null
+++ b/SOL002/VNFPerformanceManagement-API_nxw/environment/individualSubscription.txt
@@ -0,0 +1,3 @@
+*** Variables ***
+${subscriptionId}    17563e75-0e14-4bd7-94b4-6bbb869c79aa
+${erroneousSubscriptionId}    erroneousSubscriptionId
diff --git a/SOL002/VNFPerformanceManagement-API_nxw/environment/individualThresholds.txt b/SOL002/VNFPerformanceManagement-API_nxw/environment/individualThresholds.txt
new file mode 100644
index 00000000..59056904
--- /dev/null
+++ b/SOL002/VNFPerformanceManagement-API_nxw/environment/individualThresholds.txt
@@ -0,0 +1,3 @@
+*** Variables ***
+${thresholdId}    1f50d68b-82e8-4deb-bd40-c934d4d1ac0a
+${erroneousThresholdId}    erroneousThresholdId
diff --git a/SOL002/VNFPerformanceManagement-API_nxw/environment/pmJobs.txt b/SOL002/VNFPerformanceManagement-API_nxw/environment/pmJobs.txt
new file mode 100644
index 00000000..57798d17
--- /dev/null
+++ b/SOL002/VNFPerformanceManagement-API_nxw/environment/pmJobs.txt
@@ -0,0 +1,4 @@
+*** Variables ***
+${POS_FILTER}     objectInstanceIds=1f50d68b-82e8-4deb-bd40-c934d4d1ac0a
+${NEG_FILTER}     criteriaPmJob=erroneousAttributeName
+${fields}         criteria,reports
diff --git a/SOL002/VNFPerformanceManagement-API_nxw/environment/reports.txt b/SOL002/VNFPerformanceManagement-API_nxw/environment/reports.txt
new file mode 100644
index 00000000..7edfcc5c
--- /dev/null
+++ b/SOL002/VNFPerformanceManagement-API_nxw/environment/reports.txt
@@ -0,0 +1,4 @@
+*** Variables ***
+${pmJobId}        1f50d68b-82e8-4deb-bd40-c934d4d1ac0a
+${reportId}       0fb4c875-e07f-46ca-a9dd-13907667a568
+${erroneousReportId}    erroneousReportId
diff --git a/SOL002/VNFPerformanceManagement-API_nxw/environment/subscriptions.txt b/SOL002/VNFPerformanceManagement-API_nxw/environment/subscriptions.txt
new file mode 100644
index 00000000..fec8c84b
--- /dev/null
+++ b/SOL002/VNFPerformanceManagement-API_nxw/environment/subscriptions.txt
@@ -0,0 +1,3 @@
+*** Variables ***
+${filter_ok}      callbackUri=http://localhost/subscriptions
+${filter_ko}      erroneousFilter=erroneous
diff --git a/SOL002/VNFPerformanceManagement-API_nxw/environment/thresholds.txt b/SOL002/VNFPerformanceManagement-API_nxw/environment/thresholds.txt
new file mode 100644
index 00000000..49461a09
--- /dev/null
+++ b/SOL002/VNFPerformanceManagement-API_nxw/environment/thresholds.txt
@@ -0,0 +1,3 @@
+*** Variables ***
+${FILTER_OK}      objectInstanceId=1f50d68b-82e8-4deb-bd40-c934d4d1ac0a
+${FILTER_KO}      criterias=erroneousFilter
diff --git a/SOL002/VNFPerformanceManagement-API_nxw/jsons/CreatePmJobRequest.json b/SOL002/VNFPerformanceManagement-API_nxw/jsons/CreatePmJobRequest.json
new file mode 100644
index 00000000..1872a3bc
--- /dev/null
+++ b/SOL002/VNFPerformanceManagement-API_nxw/jsons/CreatePmJobRequest.json
@@ -0,0 +1,10 @@
+{
+	"objectInstanceIds" : ["1f50d68b-82e8-4deb-bd40-c934d4d1ac0a"],
+	"criteria" : {
+		"performanceMetric": [],
+		"performanceMetricGroup": [],
+		"collectionPeriod": 10,
+		"reportingPeriod": 30,
+		
+	}
+}
\ No newline at end of file
diff --git a/SOL002/VNFPerformanceManagement-API_nxw/jsons/CreateThresholdRequest.json b/SOL002/VNFPerformanceManagement-API_nxw/jsons/CreateThresholdRequest.json
new file mode 100644
index 00000000..1e58c2ba
--- /dev/null
+++ b/SOL002/VNFPerformanceManagement-API_nxw/jsons/CreateThresholdRequest.json
@@ -0,0 +1,12 @@
+{
+	"objectInstanceIds" : "1f50d68b-82e8-4deb-bd40-c934d4d1ac0a",
+	"criteria" : {
+		"performanceMetric": "cpu_util",
+		"thresholdType": "SIMPLE",
+		"simpleThresholdDetails": {
+			"thresholdValue": 10,
+			"hysteresis": 50
+		}
+		
+	}
+}
\ No newline at end of file
diff --git a/SOL002/VNFPerformanceManagement-API_nxw/jsons/subscriptions.json b/SOL002/VNFPerformanceManagement-API_nxw/jsons/subscriptions.json
new file mode 100644
index 00000000..3fcc4e59
--- /dev/null
+++ b/SOL002/VNFPerformanceManagement-API_nxw/jsons/subscriptions.json
@@ -0,0 +1,6 @@
+{
+	"callbackUri": "http://127.0.0.1/subscribe",
+	"filter": {
+		"notificationTypes": ["ThresholdCrossedNotification"]
+	}
+}
\ No newline at end of file
diff --git a/SOL002/VNFPerformanceManagement-API_nxw/schemas/PerformanceReport.schema.json b/SOL002/VNFPerformanceManagement-API_nxw/schemas/PerformanceReport.schema.json
new file mode 100644
index 00000000..c0a9c444
--- /dev/null
+++ b/SOL002/VNFPerformanceManagement-API_nxw/schemas/PerformanceReport.schema.json
@@ -0,0 +1 @@
+{  "description": "This type defines the format of a performance report provided by the VNFM to the NFVO as a result of collecting performance information as part of a PM job.\n",  "type": "object",  "properties": {    "entries": {      "description": "List of performance information entries. Each performance report entry is for a given metric of a given object (i.e. VNF instance), but can include multiple collected values.\n",      "type": "array",      "items": {        "type": "object",        "required": [          "objectType",          "objectInstanceId",          "performanceMetric",          "performanceValue"        ],        "properties": {          "objectType": {            "description": "Defines the object type for which performance information is reported (i.e. VNF type). The string value shall be set to the vnfdId of the VNF instance to which the performance information relates.\n",            "type": "string"          },          "objectInstanceId": {            "description": "An identifier with the intention of being globally unique.\n",            "type": "string"          },          "performanceMetric": {            "description": "Name of the metric collected.\n",            "type": "string"          },          "performanceValues": {            "description": "List of performance values with associated timestamp.\n",            "type": "array",            "items": {              "type": "object",              "required": [                "timeStamp",                "performanceValue"              ],              "properties": {                "timeStamp": {                  "description": "Date-time stamp.  Representation: String formatted according to IETF RFC 3339.\n",                  "type": "string",                  "format": "date-time"                },                "value": {                  "description": "Value of the metric collected. The type of the \"value\" attribute (i.e. scalar, structure (Object in JSON), or array (of scalars, arrays or structures / Objects)) is assumed to be defined in the external measurement specification (see ETSI GS NFV-IFA 027).\n",                  "type": "object"                }              }            }          }        }      }    }  }}
\ No newline at end of file
diff --git a/SOL002/VNFPerformanceManagement-API_nxw/schemas/PmJob.schema.json b/SOL002/VNFPerformanceManagement-API_nxw/schemas/PmJob.schema.json
new file mode 100644
index 00000000..65121412
--- /dev/null
+++ b/SOL002/VNFPerformanceManagement-API_nxw/schemas/PmJob.schema.json
@@ -0,0 +1 @@
+{  "description": "This type represents a PM job.\n",  "type": "object",  "required": [    "id",    "objectInstanceIds",    "criteria"  ],  "properties": {    "id": {      "description": "An identifier with the intention of being globally unique.\n",      "type": "string"    },    "objectInstanceIds": {      "description": "Identifiers of the VNF instances for which performance information is collected.\n",      "type": "array",      "items": {        "description": "An identifier with the intention of being globally unique.\n",        "type": "string"      }    },    "criteria": {      "description": "Criteria of the collection of performance information.\n",      "type": "object",      "required": [        "collectionPeriod",        "reportingPeriod"      ],      "properties": {        "performanceMetric": {          "description": "This defines the types of performance metrics for the specified object instances, as specified in ETSI GS NFV-IFA 027). At least one of the two attributes (performance metric or group) shall be present.\n",          "type": "array",          "items": {            "type": "string"          }        },        "performanceMetricGroup": {          "description": "Group of performance metrics. A metric group is a pre-defined list of metrics, known to the producer that it can decompose to individual metrics. At least one of the two attributes (performance metric or group) shall be present.\n",          "type": "array",          "items": {            "type": "string"          }        },        "collectionPeriod": {          "description": "Specifies the periodicity at which the producer will collect performance information. The unit shall be seconds. At the end of each reportingPeriod, the producer will inform the consumer about availability of the performance data collected for each completed collection period during this reportingPeriod. The reportingPeriod should be equal to or a multiple of the collectionPeriod. In the latter case, the performance data for the collection periods within one reporting period are reported together.\n",          "type": "integer"        },        "reportingPeriod": {          "description": "Specifies the periodicity at which the producer will report to the consumer. about performance information. The unit shall be seconds. At the end of each reportingPeriod, the producer will inform the consumer about availability of the performance data collected for each completed collection period during this reportingPeriod. The reportingPeriod should be equal to or a multiple of the collectionPeriod. In the latter case, the performance data for the collection periods within one reporting period are reported together.\n",          "type": "integer"        },        "reportingBoundary": {          "description": "Date-time stamp.  Representation: String formatted according to IETF RFC 3339.\n",          "type": "string",          "format": "date-time"        }      }    },    "reports": {      "description": "Information about available reports collected by this PM job.\n",      "type": "object",      "required": [        "href",        "readyTime",        "_links"      ],      "properties": {        "href": {          "description": "The Uri where the report can be obtained.\n",          "type": "string",          "format": "url"        },        "readyTime": {          "description": "Date-time stamp.  Representation: String formatted according to IETF RFC 3339.\n",          "type": "string",          "format": "date-time"        },        "expiryTime": {          "description": "Date-time stamp.  Representation: String formatted according to IETF RFC 3339.\n",          "type": "string",          "format": "date-time"        },        "fileSize": {          "description": "The size of the report file in bytes, if known.\n",          "type": "integer"        },        "_links": {          "description": "Links for this resource.\n",          "type": "object",          "required": [            "self"          ],          "properties": {            "self": {              "description": "This type represents a link to a resource.\n",              "type": "object",              "required": [                "href"              ],              "properties": {                "href": {                  "description": "URI of the referenced resource.\n",                  "type": "string",                  "format": "url"                }              }            },            "objects": {              "description": "Links to resources representing the VNF instances for which performance information is collected. Shall be present if the VNF instance information is accessible as a resource.\n",              "type": "array",              "items": {                "description": "This type represents a link to a resource.\n",                "type": "object",                "required": [                  "href"                ],                "properties": {                  "href": {                    "description": "URI of the referenced resource.\n",                    "type": "string",                    "format": "url"                  }                }              }            }          }        }      }    }  }}
\ No newline at end of file
diff --git a/SOL002/VNFPerformanceManagement-API_nxw/schemas/PmSubscriptions.schema.json b/SOL002/VNFPerformanceManagement-API_nxw/schemas/PmSubscriptions.schema.json
new file mode 100644
index 00000000..fefb142d
--- /dev/null
+++ b/SOL002/VNFPerformanceManagement-API_nxw/schemas/PmSubscriptions.schema.json
@@ -0,0 +1 @@
+{  "type": "array",  "items": {    "description": "This type represents a subscription.\n",    "type": "object",    "required": [      "id",      "callbackUri",      "_links"    ],    "properties": {      "id": {        "description": "An identifier with the intention of being globally unique.\n",        "type": "string"      },      "filter": {        "description": "This type represents a filter that can be used to subscribe for notifications related to performance management events.\n",        "type": "object",        "properties": {          "vnfInstanceSubscriptionFilter": {            "description": "This type represents subscription filter criteria to match VNF instances.\n",            "type": "object",            "properties": {              "vnfdIds": {                "description": "If present, match VNF instances that were created based on a VNFD identified by one of the vnfdId values listed in this attribute. The attributes \"vnfdIds\" and \"vnfProductsFromProviders\" are alternatives to reference to VNF instances that are based on certain VNFDs in a filter. They should not be used both in the same filter instance, but one alternative should be chosen.\n",                "type": "array",                "items": {                  "description": "An identifier with the intention of being globally unique.\n",                  "type": "string"                }              },              "vnfProductsFromProviders": {                "description": "If present, match VNF instances that belong to VNF products from certain providers. The attributes \"vnfdIds\" and \"vnfProductsFromProviders\" are alternatives to reference to VNF instances that are based on certain VNFDs in a filter. They should not be used both in the same filter instance, but one alternative should be chosen.\n",                "type": "array",                "items": {                  "type": "object",                  "required": [                    "vnfProvider"                  ],                  "properties": {                    "vnfProvider": {                      "description": "Name of the VNF provider to match.\n",                      "type": "string"                    },                    "vnfProducts": {                      "description": "If present, match VNF instances that belong to VNF products with certain product names, from one particular provider.\n",                      "type": "array",                      "items": {                        "type": "object",                        "required": [                          "vnfProductName"                        ],                        "properties": {                          "vnfProductName": {                            "description": "Name of the VNF product to match.\n",                            "type": "string"                          },                          "versions": {                            "description": "If present, match VNF instances that belong to VNF products with certain versions and a certain product name, from one particular provider.\n",                            "type": "array",                            "items": {                              "type": "object",                              "required": [                                "vnfSoftwareVersion"                              ],                              "properties": {                                "vnfSoftwareVersion": {                                  "description": "A version.\n",                                  "type": "string"                                },                                "vnfdVersions": {                                  "description": "If present, match VNF instances that belong to VNF products with certain VNFD versions, a certain software version and a certain product name, from one particular provider.\n",                                  "type": "array",                                  "items": {                                    "description": "A version.\n",                                    "type": "string"                                  }                                }                              }                            }                          }                        }                      }                    }                  }                }              },              "vnfInstanceIds": {                "description": "If present, match VNF instances with an instance identifier listed in this attribute. The attributes \"vnfInstanceIds\" and \"vnfInstanceNames\" are alternatives to reference to particular VNF Instances in a filter. They should not be used both in the same filter instance, but one alternative should be chosen.\n",                "type": "array",                "items": {                  "description": "An identifier with the intention of being globally unique.\n",                  "type": "string"                }              },              "vnfInstanceNames": {                "description": "If present, match VNF instances with a VNF Instance Name listed in this attribute. The attributes \"vnfInstanceIds\" and \"vnfInstanceNames\" are alternatives to reference to particular VNF Instances in a filter. They should not be used both in the same filter instance, but one alternative should be chosen.\n",                "type": "array",                "items": {                  "type": "string"                }              }            }          },          "notificationTypes": {            "description": "Match particular notification types. Permitted values: * ThresholdCrossedNotification * PerformanceInformationAvailableNotification The permitted values of the \"notificationTypes\" attribute are spelled exactly as the names of the notification types to facilitate automated code generation systems.\n",            "type": "string",            "enum": [              "ThresholdCrossedNotification",              "PerformanceInformationAvailableNotification"            ]          }        }      },      "callbackUri": {        "description": "The URI of the endpoint to send the notification to.\n",        "type": "string",        "format": "url"      },      "_links": {        "description": "Links to resources related to this resource.\n",        "type": "object",        "required": [          "self"        ],        "properties": {          "self": {            "description": "This type represents a link to a resource.\n",            "type": "object",            "required": [              "href"            ],            "properties": {              "href": {                "description": "URI of the referenced resource.\n",                "type": "string",                "format": "url"              }            }          }        }      }    }  }}
\ No newline at end of file
diff --git a/SOL002/VNFPerformanceManagement-API_nxw/schemas/ProblemDetails.schema.json b/SOL002/VNFPerformanceManagement-API_nxw/schemas/ProblemDetails.schema.json
new file mode 100644
index 00000000..2af3ef9b
--- /dev/null
+++ b/SOL002/VNFPerformanceManagement-API_nxw/schemas/ProblemDetails.schema.json
@@ -0,0 +1 @@
+{  "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n",  "type": "object",  "required": [    "status",    "detail"  ],  "properties": {    "type": {      "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n",      "type": "string",      "format": "URI"    },    "title": {      "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type.  It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n",      "type": "string"    },    "status": {      "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n",      "type": "integer"    },    "detail": {      "description": "A human-readable explanation specific to this occurrence of the problem.\n",      "type": "string"    },    "instance": {      "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n",      "type": "string",      "format": "URI"    }  }}
\ No newline at end of file
diff --git a/SOL002/VNFPerformanceManagement-API_nxw/schemas/Subscriptions.schema.json b/SOL002/VNFPerformanceManagement-API_nxw/schemas/Subscriptions.schema.json
new file mode 100644
index 00000000..fefb142d
--- /dev/null
+++ b/SOL002/VNFPerformanceManagement-API_nxw/schemas/Subscriptions.schema.json
@@ -0,0 +1 @@
+{  "type": "array",  "items": {    "description": "This type represents a subscription.\n",    "type": "object",    "required": [      "id",      "callbackUri",      "_links"    ],    "properties": {      "id": {        "description": "An identifier with the intention of being globally unique.\n",        "type": "string"      },      "filter": {        "description": "This type represents a filter that can be used to subscribe for notifications related to performance management events.\n",        "type": "object",        "properties": {          "vnfInstanceSubscriptionFilter": {            "description": "This type represents subscription filter criteria to match VNF instances.\n",            "type": "object",            "properties": {              "vnfdIds": {                "description": "If present, match VNF instances that were created based on a VNFD identified by one of the vnfdId values listed in this attribute. The attributes \"vnfdIds\" and \"vnfProductsFromProviders\" are alternatives to reference to VNF instances that are based on certain VNFDs in a filter. They should not be used both in the same filter instance, but one alternative should be chosen.\n",                "type": "array",                "items": {                  "description": "An identifier with the intention of being globally unique.\n",                  "type": "string"                }              },              "vnfProductsFromProviders": {                "description": "If present, match VNF instances that belong to VNF products from certain providers. The attributes \"vnfdIds\" and \"vnfProductsFromProviders\" are alternatives to reference to VNF instances that are based on certain VNFDs in a filter. They should not be used both in the same filter instance, but one alternative should be chosen.\n",                "type": "array",                "items": {                  "type": "object",                  "required": [                    "vnfProvider"                  ],                  "properties": {                    "vnfProvider": {                      "description": "Name of the VNF provider to match.\n",                      "type": "string"                    },                    "vnfProducts": {                      "description": "If present, match VNF instances that belong to VNF products with certain product names, from one particular provider.\n",                      "type": "array",                      "items": {                        "type": "object",                        "required": [                          "vnfProductName"                        ],                        "properties": {                          "vnfProductName": {                            "description": "Name of the VNF product to match.\n",                            "type": "string"                          },                          "versions": {                            "description": "If present, match VNF instances that belong to VNF products with certain versions and a certain product name, from one particular provider.\n",                            "type": "array",                            "items": {                              "type": "object",                              "required": [                                "vnfSoftwareVersion"                              ],                              "properties": {                                "vnfSoftwareVersion": {                                  "description": "A version.\n",                                  "type": "string"                                },                                "vnfdVersions": {                                  "description": "If present, match VNF instances that belong to VNF products with certain VNFD versions, a certain software version and a certain product name, from one particular provider.\n",                                  "type": "array",                                  "items": {                                    "description": "A version.\n",                                    "type": "string"                                  }                                }                              }                            }                          }                        }                      }                    }                  }                }              },              "vnfInstanceIds": {                "description": "If present, match VNF instances with an instance identifier listed in this attribute. The attributes \"vnfInstanceIds\" and \"vnfInstanceNames\" are alternatives to reference to particular VNF Instances in a filter. They should not be used both in the same filter instance, but one alternative should be chosen.\n",                "type": "array",                "items": {                  "description": "An identifier with the intention of being globally unique.\n",                  "type": "string"                }              },              "vnfInstanceNames": {                "description": "If present, match VNF instances with a VNF Instance Name listed in this attribute. The attributes \"vnfInstanceIds\" and \"vnfInstanceNames\" are alternatives to reference to particular VNF Instances in a filter. They should not be used both in the same filter instance, but one alternative should be chosen.\n",                "type": "array",                "items": {                  "type": "string"                }              }            }          },          "notificationTypes": {            "description": "Match particular notification types. Permitted values: * ThresholdCrossedNotification * PerformanceInformationAvailableNotification The permitted values of the \"notificationTypes\" attribute are spelled exactly as the names of the notification types to facilitate automated code generation systems.\n",            "type": "string",            "enum": [              "ThresholdCrossedNotification",              "PerformanceInformationAvailableNotification"            ]          }        }      },      "callbackUri": {        "description": "The URI of the endpoint to send the notification to.\n",        "type": "string",        "format": "url"      },      "_links": {        "description": "Links to resources related to this resource.\n",        "type": "object",        "required": [          "self"        ],        "properties": {          "self": {            "description": "This type represents a link to a resource.\n",            "type": "object",            "required": [              "href"            ],            "properties": {              "href": {                "description": "URI of the referenced resource.\n",                "type": "string",                "format": "url"              }            }          }        }      }    }  }}
\ No newline at end of file
diff --git a/SOL002/VNFPerformanceManagement-API_nxw/schemas/Threshold.schema.json b/SOL002/VNFPerformanceManagement-API_nxw/schemas/Threshold.schema.json
new file mode 100644
index 00000000..d642b93f
--- /dev/null
+++ b/SOL002/VNFPerformanceManagement-API_nxw/schemas/Threshold.schema.json
@@ -0,0 +1 @@
+{  "type": "array",  "items": {    "description": "This type represents a threshold.\n",    "type": "object",    "required": [      "id",      "objectInstanceId",      "criteria",      "_links"    ],    "properties": {      "id": {        "description": "An identifier with the intention of being globally unique.\n",        "type": "string"      },      "objectInstanceId": {        "description": "An identifier with the intention of being globally unique.\n",        "type": "string"      },      "criteria": {        "description": "This type represents criteria that define a threshold.\n",        "type": "object",        "required": [          "performanceMetric",          "thresholdType"        ],        "properties": {          "performanceMetric": {            "description": "Defines the performance metric associated with the threshold, as specified in ETSI GS NFV-IFA 027).\n",            "type": "string"          },          "thresholdType": {            "description": "Type of threshold. This attribute determines which other attributes are present in the data structure. Permitted values: * SIMPLE: Single-valued static threshold In the present document, simple thresholds are defined. The definition of additional threshold types is left for future specification.\n",            "type": "string",            "enum": [              "SIMPLE"            ]          },          "simpleThresholdDetails": {            "description": "Details of a simple threshold. Shall be present if thresholdType=\"SIMPLE\".\n",            "type": "object",            "required": [              "thresholdValue",              "hysteresis"            ],            "properties": {              "thresholdValue": {                "description": "The threshold value. Shall be represented as a floating point number.\n",                "type": "integer"              },              "hysteresis": {                "description": "The hysteresis of the threshold. Shall be represented as a non-negative floating point number. A notification with crossing direction \"UP\" will be generated if the measured value reaches or exceeds \"thresholdValue\" + \"hysteresis\". A notification with crossing direction \"DOWN\" will be generated if the measured value reaches or undercuts \"thresholdValue\" - \"hysteresis\". The hysteresis is defined to prevent storms of threshold crossing notifications. When processing a request to create a threshold, implementations should enforce a suitable minimum value for this attribute (e.g. override the value or reject the request).\n",                "type": "integer"              }            }          }        }      },      "_links": {        "description": "Links for this resource.\n",        "type": "object",        "required": [          "self"        ],        "properties": {          "self": {            "description": "This type represents a link to a resource.\n",            "type": "object",            "required": [              "href"            ],            "properties": {              "href": {                "description": "URI of the referenced resource.\n",                "type": "string",                "format": "url"              }            }          },          "object": {            "description": "Link to a resource representing the VNF instance for which performance information is collected. Shall be present if the VNF instance information is accessible as a resource.\n"          }        }      }    }  }}
\ No newline at end of file
diff --git a/SOL002/VNFPerformanceManagement-API_nxw/schemas/criteria.schema.json b/SOL002/VNFPerformanceManagement-API_nxw/schemas/criteria.schema.json
new file mode 100644
index 00000000..319d15f5
--- /dev/null
+++ b/SOL002/VNFPerformanceManagement-API_nxw/schemas/criteria.schema.json
@@ -0,0 +1,34 @@
+{
+	"description": "Criteria of the collection of performance information.\n",
+	"type": "object",
+	"required": ["collectionPeriod", "reportingPeriod"],
+	"properties": {
+		"performanceMetric": {
+			"description": "This defines the types of performance metrics for the specified object instances, as specified in ETSI GS NFV-IFA 027). At least one of the two attributes (performance metric or group) shall be present.\n",
+			"type": "array",
+			"items": {
+				"type": "string"
+			}
+		},
+		"performanceMetricGroup": {
+			"description": "Group of performance metrics. A metric group is a pre-defined list of metrics, known to the producer that it can decompose to individual metrics. At least one of the two attributes (performance metric or group) shall be present.\n",
+			"type": "array",
+			"items": {
+				"type": "string"
+			}
+		},
+		"collectionPeriod": {
+			"description": "Specifies the periodicity at which the producer will collect performance information. The unit shall be seconds. At the end of each reportingPeriod, the producer will inform the consumer about availability of the performance data collected for each completed collection period during this reportingPeriod. The reportingPeriod should be equal to or a multiple of the collectionPeriod. In the latter case, the performance data for the collection periods within one reporting period are reported together.\n",
+			"type": "integer"
+		},
+		"reportingPeriod": {
+			"description": "Specifies the periodicity at which the producer will report to the consumer. about performance information. The unit shall be seconds. At the end of each reportingPeriod, the producer will inform the consumer about availability of the performance data collected for each completed collection period during this reportingPeriod. The reportingPeriod should be equal to or a multiple of the collectionPeriod. In the latter case, the performance data for the collection periods within one reporting period are reported together.\n",
+			"type": "integer"
+		},
+		"reportingBoundary": {
+			"description": "Date-time stamp.  Representation: String formatted according to IETF RFC 3339.\n",
+			"type": "string",
+			"format": "date-time"
+		}
+	}
+}
\ No newline at end of file
diff --git a/SOL002/VNFPerformanceManagement-API_nxw/schemas/links.schema.json b/SOL002/VNFPerformanceManagement-API_nxw/schemas/links.schema.json
new file mode 100644
index 00000000..ef262a8c
--- /dev/null
+++ b/SOL002/VNFPerformanceManagement-API_nxw/schemas/links.schema.json
@@ -0,0 +1,35 @@
+{
+	"description": "Links for this resource.\n",
+	"type": "object",
+	"required": ["self"],
+	"properties": {
+		"self": {
+			"description": "This type represents a link to a resource.\n",
+			"type": "object",
+			"required": ["href"],
+			"properties": {
+				"href": {
+					"description": "URI of the referenced resource.\n",
+					"type": "string",
+					"format": "url"
+				}
+			}
+		},
+		"objects": {
+			"description": "Links to resources representing the VNF instances for which performance information is collected. Shall be present if the VNF instance information is accessible as a resource.\n",
+			"type": "array",
+			"items": {
+				"description": "This type represents a link to a resource.\n",
+				"type": "object",
+				"required": ["href"],
+				"properties": {
+					"href": {
+						"description": "URI of the referenced resource.\n",
+						"type": "string",
+						"format": "url"
+					}
+				}
+			}
+		}
+	}
+}
\ No newline at end of file
diff --git a/SOL002/VNFPerformanceManagement-API_nxw/schemas/reports.schema.json b/SOL002/VNFPerformanceManagement-API_nxw/schemas/reports.schema.json
new file mode 100644
index 00000000..834ded68
--- /dev/null
+++ b/SOL002/VNFPerformanceManagement-API_nxw/schemas/reports.schema.json
@@ -0,0 +1,26 @@
+{
+	"description": "Information about available reports collected by this PM job.\n",
+	"type": "object",
+	"required": ["href", "readyTime"],
+	"properties": {
+		"href": {
+			"description": "The Uri where the report can be obtained.\n",
+			"type": "string",
+			"format": "url"
+		},
+		"readyTime": {
+			"description": "Date-time stamp.  Representation: String formatted according to IETF RFC 3339.\n",
+			"type": "string",
+			"format": "date-time"
+		},
+		"expiryTime": {
+			"description": "Date-time stamp.  Representation: String formatted according to IETF RFC 3339.\n",
+			"type": "string",
+			"format": "date-time"
+		},
+		"fileSize": {
+			"description": "The size of the report file in bytes, if known.\n",
+			"type": "integer"
+		}
+	}
+}
\ No newline at end of file
diff --git a/TrackingStatus.txt b/TrackingStatus.txt
index 9b9a9c90..f1d5957c 100644
--- a/TrackingStatus.txt
+++ b/TrackingStatus.txt
@@ -16,10 +16,10 @@ SOL002
   - VNFLifecycleManagement-API_egm --------------------------> [NOT STARTED]
 
   - VNFPerformanceManagement-API_nxw ------------------------> [IN PROGRESS]
-    * PMJobs ----------------------------------------------------> [IN PROGRESS]
-    * IndividualPmJob -------------------------------------------> [NOT STARTED]
-    * IndividualReport-------------------------------------------> [NOT STARTED]
-    * Thresholds ------------------------------------------------> [NOT STARTED]
+    * PMJobs ----------------------------------------------------> [DONE]
+    * IndividualPmJob -------------------------------------------> [DONE]
+    * IndividualReport-------------------------------------------> [DONE]
+    * Thresholds ------------------------------------------------> [IN PROGRESS]
     * IndividualThreshold ---------------------------------------> [NOT STARTED]
     * Subscriptions ---------------------------------------------> [NOT STARTED]
     * IndividualSubscription ------------------------------------> [NOT STARTED]
-- 
GitLab