diff --git a/.github/workflows/pr_validation_caller.yml b/.github/workflows/pr_validation_caller.yml new file mode 100644 index 0000000..d847f6e --- /dev/null +++ b/.github/workflows/pr_validation_caller.yml @@ -0,0 +1,49 @@ +# ========================================================================================= +# CAMARA Project - Pull Request Validation Workflow Caller +# +# This GitHub Actions workflow is responsible for invoking a reusable PR validation workflow +# from the camaraproject/tooling repository. It is intended to ensure consistent validation +# steps for all PRs targeting the main branch in this repository. +# +# CHANGELOG: +# - 2025-08-01: Initial version for v0 +# +# USAGE: +# - Automatically triggers on pull requests targeting main. +# - Can be triggered manually via workflow_dispatch. +# - Calls by default the reusable workflow at +# camaraproject/tooling/.github/workflows/pr_validation.yml@v0 +# +# DOCUMENTATION: +# see https://github.com/camaraproject/tooling/tree/main/linting/docs +# ========================================================================================= + +name: Caller for PR validation workflow + +on: + # Trigger on pull requests to the main branch only + pull_request: + branches: main + # Enable manual trigger via the GitHub UI + workflow_dispatch: + +concurrency: + group: ${{ github.ref }}-${{ github.workflow }} + cancel-in-progress: true + +permissions: + # Grant necessary write permissions for PRs, contents, and issues + pull-requests: write + contents: write + issues: write + statuses: write + +jobs: + pr_validation: + # Invoke the reusable PR validation workflow from "v0" tag of camaraproject/tooling + uses: camaraproject/tooling/.github/workflows/pr_validation.yml@v0 + secrets: inherit +# Tools configuration from the tooling repository subfolder of /linting/config/ indicated by `configurations` variable +# If needed, you can specify a configuration from another subfolder of camaraproject/tooling/linting/config/ (uncomment below) +# with: +# configurations: api-name diff --git a/.github/workflows/spectral-oas-caller.yml b/.github/workflows/spectral-oas-caller.yml new file mode 100644 index 0000000..05cde3f --- /dev/null +++ b/.github/workflows/spectral-oas-caller.yml @@ -0,0 +1,42 @@ +# ========================================================================================= +# CAMARA Project - Linting OpenAPI Specification with CAMARA Ruleset Caller +# +# This GitHub Actions workflow is responsible for invoking a reusable "Spectral linting with +# CAMARA ruleset" workflow from the camaraproject/tooling repository. It is intended to +# provide more detailed output from Spectral tool (warnings, hints) +# +# CHANGELOG: +# - 2025-08-01: Initial version for v0 +# +# USAGE: +# - Can be triggered manually via workflow_dispatch. +# - Calls by default the reusable workflow at +# camaraproject/tooling/.github/workflows/spectral-oas.yml@v0 +# +# DOCUMENTATION: +# see https://github.com/camaraproject/tooling/tree/main/linting/docs +# ========================================================================================= + +name: Caller for Spectral linting with CAMARA ruleset + +on: + workflow_dispatch: + +concurrency: + group: ${{ github.ref }}-${{ github.workflow }} + cancel-in-progress: true + +permissions: + # Grant necessary write permissions for PRs and issues + pull-requests: write + contents: read + issues: write + +jobs: + spectral: + # Invoke the reusable PR validation workflow from the main branch of camaraproject/tooling + uses: camaraproject/tooling/.github/workflows/spectral-oas.yml@v0 +# Spectral configuration from the tooling repository subfolder of /linting/config/ indicated by `configurations` variable +# If needed, you can specify a configuration from another subfolder of camaraproject/tooling/linting/config/ (uncomment below) +# with: +# configurations: api-name diff --git a/code/API_definitions/device-swap.yaml b/code/API_definitions/device-swap.yaml index fb3a4bc..fcd8155 100644 --- a/code/API_definitions/device-swap.yaml +++ b/code/API_definitions/device-swap.yaml @@ -6,7 +6,7 @@ info: # Introduction - The Device Swap API performs real-time checks on the last Device Swap event, providing real-time information about whether the SIM card associated with a user's phone number has been transferred to a different physical device. + The Device Swap API performs real-time checks on the last Device Swap event, providing real-time information about whether the SIM card associated with a user's phone number has been transferred to a different physical device. Device Swap information can be invaluable for enhancing security, fraud detection, and ensuring compliance with regulatory requirements in various applications, apart from providing useful information of device upgrade trends in user segments. @@ -22,7 +22,7 @@ info: # API Functionality The Device Swap API provides a programmable interface for developers and other users (capabilities consumers) to request the last date of a device swap performed on the mobile line, or, to check whether a device swap has been performed during a past period. - + The API provides 2 operations: - POST retrieve-date: Provides timestamp of latest device swap, if any, for a given phone number. @@ -81,7 +81,7 @@ tags: description: Receive the last date in which the device of the end-user was swapped - name: Check Device Swap description: Validate if the SIM of the end-user has been installed in a different device during a past period -paths: +paths: /retrieve-date: post: tags: @@ -91,9 +91,9 @@ paths: operationId: retrieveDeviceSwapDate security: - openId: - - device-swap + - device-swap - openId: - - device-swap:retrieve-date + - device-swap:retrieve-date parameters: - $ref: '#/components/parameters/x-correlator' requestBody: @@ -145,9 +145,9 @@ paths: operationId: checkDeviceSwap security: - openId: - - device-swap + - device-swap - openId: - - device-swap:check + - device-swap:check parameters: - $ref: '#/components/parameters/x-correlator' requestBody: @@ -268,7 +268,7 @@ components: description: Code given to this error message: type: string - description: Detailed error description + description: Detailed error description responses: Generic400: description: Bad Request @@ -288,8 +288,7 @@ components: message: Client specified an invalid argument, request body or query param. Generic400Check: description: |- - Bad Request - + Bad Request In addition to regular scenario of INVALID_ARGUMENT, other scenarios may exist: - Out of Range. Specific Syntax Exception used when a given field has a pre-defined range or a invalid filter criteria combination is requested ("code": "OUT_OF_RANGE","message": "Client specified an invalid range.") headers: diff --git a/code/Test_definitions/checkDeviceSwap.feature b/code/Test_definitions/checkDeviceSwap.feature index e2b74b3..00f4f00 100644 --- a/code/Test_definitions/checkDeviceSwap.feature +++ b/code/Test_definitions/checkDeviceSwap.feature @@ -3,211 +3,209 @@ Feature: CAMARA Device Swap API, wip - Operation checkDeviceSwap # Input to be provided by the implementation to the tester # # Testing assets: - # - # References to OAS spec schemas refer to schemas specifies in device-swap.yaml, version wip - # - # Check if device swap has been performed during a past period - - - Background: Common checkDeviceSwap setup - Given the resource "device-swap/vwip/check" - And the header "Content-Type" is set to "application/json" - And the header "Authorization" is set to a valid access token - And the header "x-correlator" complies with the schema at "#/components/schemas/XCorrelator" - And the request body is set by default to a request body compliant with the schema - - # This first scenario serves as a minimum, not testing any specific verificationResult - @check_device_swap_1_generic_success_scenario - Scenario: Common validations for any sucess scenario - Given a valid phone number identified by the token or provided in the request body - When the request "checkDeviceSwap" is sent - Then the response status code is 200 - And the response header "Content-Type" is "application/json" - And the response header "x-correlator" has same value as the request header "x-correlator" - And the response body complies with the OAS schema at "/components/schemas/CheckDeviceSwapInfo" + # * A device object which a device swap occured in the last 240 hours. + # * for additional testing another device without device swapping last 240 hours. + # References to OAS spec schemas refer to schemas specifies in device-swap.yaml + + Background: Common checkDeviceSwap setup + Given the resource "device-swap/vwip/check" + And the header "Content-Type" is set to "application/json" + And the header "Authorization" is set to a valid access token + And the header "x-correlator" complies with the schema at "#/components/schemas/XCorrelator" + And the request body is set by default to a request body compliant with the schema + + # This first scenario serves as a minimum, not testing any specific verificationResult + @check_device_swap_1_generic_success_scenario + Scenario: Common validations for any sucess scenario + Given a valid phone number identified by the token or provided in the request body + When the request "checkDeviceSwap" is sent + Then the response status code is 200 + And the response header "Content-Type" is "application/json" + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response body complies with the OAS schema at "/components/schemas/CheckDeviceSwapInfo" # Scenarios testing specific situations - @check_device_swap_2_valid_device_swap_no_max_age - Scenario: Check that the response shows that the device has been swapped using default value for maxAge - Given a valid phone number identified by the token or provided in the request body - And the device has been swapped in the last 240 hours - When the request "checkDeviceSwap" is sent - Then the response status code is 200 - And the value of response property "$.swapped" == true - - @check_device_swap_3_valid_device_swap_max_age - Scenario Outline: Check that the response shows that the device has been swapped - maxAge is provided in the request - Given a valid phone number identified by the token or provided in the request body - And the device has been swapped in the last "" - And the request body property "maxAge" is set to a value equal or greater than "" within the allowed range - When the request "checkDeviceSwap" is sent - Then the response status code is 200 - And the value of response property "$.swapped" == true - - Examples: - | hours | - | 260 | - | 120 | - | 24 | - | 12 | - - @check_device_swap_4_more_than_240_hours - Scenario: Check that the response shows that the device has not been swapped when "maxAge" is not set and the last swap was more than 240 (default) hours ago - Given a valid phone number identified by the token or provided in the request body - And the request body property "maxAge" is not setted - And the device has been swapped more than 240 hours ago - When the request "checkDeviceSwap" is sent - Then the response status code is 200 - And the value of response property "$.swapped" == false - - @check_device_swap_5_out_of_max_age - Scenario: Check that the response shows that the device has not been swapped when the last swap was before the maxAge field - Given a valid phone number identified by the token or provided in the request body - And the last swap for this phone number's in the device is known - And the request body property "maxAge" is set to a value lower that the last known device swap - When the request "checkDeviceSwap" is sent - Then the response status code is 200 - And the value of response property "$.swapped" == false - - @check_device_swap_6_no_device_swap_no_max_age - Scenario: Check that the response shows that the device has not been swapped - maxAge is not provided in the request parameter - Given a valid phone number identified by the token or provided in the request body - And the device has never been swapped - And the sim card has been associated with this device for more than 240 hours - When the request "checkDeviceSwap" is sent - Then the response status code is 200 - And the value of response property "$.swapped" == false - - @check_device_swap_7_no_device_swap_with_max_age - Scenario Outline: Check that the response shows that the device has never been swapped - maxAge is provided in the request - Given a valid phone number identified by the token or provided in the request body - And the device has never been swapped - And the sim card has been associated with this device for more than "" hours - And the request body property "maxAge" is set to a value less than "" within the allowed range - When the request "checkDeviceSwap" is sent - Then the response status code is 200 - And the value of response property "$.swapped" == false - - Examples: - | hours | - | 260 | - | 120 | - | 24 | - | 12 | + @check_device_swap_2_valid_device_swap_no_max_age + Scenario: Check that the response shows that the device has been swapped using default value for maxAge + Given a valid phone number identified by the token or provided in the request body + And the device has been swapped in the last 240 hours + When the request "checkDeviceSwap" is sent + Then the response status code is 200 + And the value of response property "$.swapped" == true + + @check_device_swap_3_valid_device_swap_max_age + Scenario Outline: Check that the response shows that the device has been swapped - maxAge is provided in the request + Given a valid phone number identified by the token or provided in the request body + And the device has been swapped in the last "" + And the request body property "maxAge" is set to a value equal or greater than "" within the allowed range + When the request "checkDeviceSwap" is sent + Then the response status code is 200 + And the value of response property "$.swapped" == true + + Examples: + | hours | + | 260 | + | 120 | + | 24 | + | 12 | + + @check_device_swap_4_more_than_240_hours + Scenario: Check that the response shows that the device has not been swapped when "maxAge" is not set and the last swap was more than 240 (default) hours ago + Given a valid phone number identified by the token or provided in the request body + And the request body property "maxAge" is not setted + And the device has been swapped more than 240 hours ago + When the request "checkDeviceSwap" is sent + Then the response status code is 200 + And the value of response property "$.swapped" == false + + @check_device_swap_5_out_of_max_age + Scenario: Check that the response shows that the device has not been swapped when the last swap was before the maxAge field + Given a valid phone number identified by the token or provided in the request body + And the last swap for this phone number's in the device is known + And the request body property "maxAge" is set to a value lower that the last known device swap + When the request "checkDeviceSwap" is sent + Then the response status code is 200 + And the value of response property "$.swapped" == false + + @check_device_swap_6_no_device_swap_no_max_age + Scenario: Check that the response shows that the device has not been swapped - maxAge is not provided in the request parameter + Given a valid phone number identified by the token or provided in the request body + And the device has never been swapped + And the sim card has been associated with this device for more than 240 hours + When the request "checkDeviceSwap" is sent + Then the response status code is 200 + And the value of response property "$.swapped" == false + + @check_device_swap_7_no_device_swap_with_max_age + Scenario Outline: Check that the response shows that the device has never been swapped - maxAge is provided in the request + Given a valid phone number identified by the token or provided in the request body + And the device has never been swapped + And the sim card has been associated with this device for more than "" hours + And the request body property "maxAge" is set to a value less than "" within the allowed range + When the request "checkDeviceSwap" is sent + Then the response status code is 200 + And the value of response property "$.swapped" == false + + Examples: + | hours | + | 260 | + | 120 | + | 24 | + | 12 | # Specific errors - # This scenario may not apply if the Operators's implementation does not allow a valid access token to be issued for a phone number that has never been connected to the network and, therefore, cannot reach the API. - @check_device_swap_8_NoDeviceSwapPhoneNumberNeverConnected - Scenario: Error when the phone number has never connected to the Operators's network so the device has never been activated - Given a valid phone number provided in the request body - And the sim for that device has never been connected to the Operator's network - When the HTTP "POST" request is sent - Then the response status code is 422 - And the response property "$.status" is 422 - And the response property "$.code" is "SERVICE_NOT_APPLICABLE" - And the response property "$.message" contains a user friendly text - - # Test cases related to the device identifier - - @check_device_swap_9_C02_01_phone_number_not_schema_compliant - Scenario: Phone number value does not comply with the schema - Given the header "Authorization" is set to a valid access token which does not identify a single phone number - And the request body property "$.phoneNumber" does not comply with the OAS schema at "/components/schemas/PhoneNumber" - When the HTTP "POST" request is sent - Then the response status code is 400 - And the response property "$.status" is 400 - And the response property "$.code" is "INVALID_ARGUMENT" - And the response property "$.message" contains a user friendly text - - @check_device_swap_10_C02_02_phone_number_not_found - Scenario: Phone number not found - Given the header "Authorization" is set to a valid access token which does not identify a single phone number - And the request body property "$.phoneNumber" is compliant with the schema but does not identify a valid phone number - When the HTTP "POST" request is sent - Then the response status code is 404 - And the response property "$.status" is 404 - And the response property "$.code" is "IDENTIFIER_NOT_FOUND" - And the response property "$.message" contains a user friendly text - - @check_device_swap_11_C02_03_unnecessary_phone_number - Scenario: Phone number not to be included when it can be deduced from the access token - Given the header "Authorization" is set to a valid access token identifying a phone number - And the request body property "$.phoneNumber" is set to a valid phone number - When the HTTP "POST" request is sent - Then the response status code is 422 - And the response property "$.status" is 422 - And the response property "$.code" is "UNNECESSARY_IDENTIFIER" - And the response property "$.message" contains a user friendly text - - @check_device_swap_12_C02_04_missing_phone_number - Scenario: Phone number not included and cannot be deducted from the access token - Given the header "Authorization" is set to a valid access token which does not identify a single phone number - And the request body property "$.phoneNumber" is not included - When the HTTP "POST" request is sent - Then the response status code is 422 - And the response property "$.status" is 422 - And the response property "$.code" is "MISSING_IDENTIFIER" - And the response property "$.message" contains a user friendly text - - @check_device_swap_13_C02_05_phone_number_not_supported - Scenario: Service not available for the phone number - Given that the service is not available for all phone numbers commercialized by the operator - And a valid phone number, identified by the token or provided in the request body, for which the service is not applicable - When the HTTP "POST" request is sent - Then the response status code is 422 - And the response property "$.status" is 422 - And the response property "$.code" is "SERVICE_NOT_APPLICABLE" - And the response property "$.message" contains a user friendly text - - # Generic 401 errors - - @check_device_swap_401.1_no_authorization_header - Scenario: No Authorization header - Given the header "Authorization" is removed - And the request body is set to a valid request body - When the HTTP "POST" request is sent - Then the response status code is "401" - And the response property "$.status" is 401 - And the response property "$.code" is "UNAUTHENTICATED" - And the response property "$.message" contains a user friendly text - - @check_device_swap_401.2_expired_access_token - Scenario: Expired access token - Given the header "Authorization" is set to an expired access token - And the request body is set to a valid request body - When the HTTP "POST" request is sent - Then the response status code is "401" - And the response property "$.status" is 401 - And the response property "$.code" is "UNAUTHENTICATED" - And the response property "$.message" contains a user friendly text - - @check_device_swap_401.3_invalid_access_token - Scenario: Invalid access token - Given the header "Authorization" is set to an invalid access token - And the request body is set to a valid request body - When the HTTP "POST" request is sent - Then the response status code is "401" - And the response property "$.status" is 401 - And the response property "$.code" is "UNAUTHENTICATED" - And the response property "$.message" contains a user friendly text - - # Generic 400 errors - - @check_device_swap_400.2_invalid_max_age - Scenario: Check that the response shows an error when the max age is invalid - Given the request body property "$.maxAge" does not comply with the OAS schema at "/components/schemas/CreateCheckDeviceSwap" - When the HTTP "POST" request is sent - Then the response status code is 400 - And the response property "$.status" is 400 - And the response property "$.code" is "INVALID_ARGUMENT" - And the response property "$.message" contains a user friendly text - - @check_device_swap_400.3_out_of_range - Scenario: Error when maxAge is out of range - Given the request body property "$.maxAge" is set to a value greater than the allowed range - When the HTTP "POST" request is sent - Then the response status code is 400 - And the response property "$.status" is 400 - And the response property "$.code" is "OUT_OF_RANGE" - And the response property "$.message" contains a user friendly text + # This scenario may not apply if the Operators's implementation does not allow a valid access token to be issued for a phone number that has never been connected to the network and, therefore, cannot reach the API. + @check_device_swap_8_NoDeviceSwapPhoneNumberNeverConnected + Scenario: Error when the phone number has never connected to the Operators's network so the device has never been activated + Given a valid phone number provided in the request body + And the sim for that device has never been connected to the Operator's network + When the HTTP "POST" request is sent + Then the response status code is 422 + And the response property "$.status" is 422 + And the response property "$.code" is "SERVICE_NOT_APPLICABLE" + And the response property "$.message" contains a user friendly text + + # Test cases related to the device identifier + + @check_device_swap_9_C02_01_phone_number_not_schema_compliant + Scenario: Phone number value does not comply with the schema + Given the header "Authorization" is set to a valid access token which does not identify a single phone number + And the request body property "$.phoneNumber" does not comply with the OAS schema at "/components/schemas/PhoneNumber" + When the HTTP "POST" request is sent + Then the response status code is 400 + And the response property "$.status" is 400 + And the response property "$.code" is "INVALID_ARGUMENT" + And the response property "$.message" contains a user friendly text + + @check_device_swap_10_C02_02_phone_number_not_found + Scenario: Phone number not found + Given the header "Authorization" is set to a valid access token which does not identify a single phone number + And the request body property "$.phoneNumber" is compliant with the schema but does not identify a valid phone number + When the HTTP "POST" request is sent + Then the response status code is 404 + And the response property "$.status" is 404 + And the response property "$.code" is "IDENTIFIER_NOT_FOUND" + And the response property "$.message" contains a user friendly text + + @check_device_swap_11_C02_03_unnecessary_phone_number + Scenario: Phone number not to be included when it can be deduced from the access token + Given the header "Authorization" is set to a valid access token identifying a phone number + And the request body property "$.phoneNumber" is set to a valid phone number + When the HTTP "POST" request is sent + Then the response status code is 422 + And the response property "$.status" is 422 + And the response property "$.code" is "UNNECESSARY_IDENTIFIER" + And the response property "$.message" contains a user friendly text + + @check_device_swap_12_C02_04_missing_phone_number + Scenario: Phone number not included and cannot be deducted from the access token + Given the header "Authorization" is set to a valid access token which does not identify a single phone number + And the request body property "$.phoneNumber" is not included + When the HTTP "POST" request is sent + Then the response status code is 422 + And the response property "$.status" is 422 + And the response property "$.code" is "MISSING_IDENTIFIER" + And the response property "$.message" contains a user friendly text + + @check_device_swap_13_C02_05_phone_number_not_supported + Scenario: Service not available for the phone number + Given that the service is not available for all phone numbers commercialized by the operator + And a valid phone number, identified by the token or provided in the request body, for which the service is not applicable + When the HTTP "POST" request is sent + Then the response status code is 422 + And the response property "$.status" is 422 + And the response property "$.code" is "SERVICE_NOT_APPLICABLE" + And the response property "$.message" contains a user friendly text + + # Generic 401 errors + + @check_device_swap_401.1_no_authorization_header + Scenario: No Authorization header + Given the header "Authorization" is removed + And the request body is set to a valid request body + When the HTTP "POST" request is sent + Then the response status code is "401" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" + And the response property "$.message" contains a user friendly text + + @check_device_swap_401.2_expired_access_token + Scenario: Expired access token + Given the header "Authorization" is set to an expired access token + And the request body is set to a valid request body + When the HTTP "POST" request is sent + Then the response status code is "401" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" + And the response property "$.message" contains a user friendly text + + @check_device_swap_401.3_invalid_access_token + Scenario: Invalid access token + Given the header "Authorization" is set to an invalid access token + And the request body is set to a valid request body + When the HTTP "POST" request is sent + Then the response status code is "401" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" + And the response property "$.message" contains a user friendly text + + # Generic 400 errors + + @check_device_swap_400.2_invalid_max_age + Scenario: Check that the response shows an error when the max age is invalid + Given the request body property "$.maxAge" does not comply with the OAS schema at "/components/schemas/CreateCheckDeviceSwap" + When the HTTP "POST" request is sent + Then the response status code is 400 + And the response property "$.status" is 400 + And the response property "$.code" is "INVALID_ARGUMENT" + And the response property "$.message" contains a user friendly text + + @check_device_swap_400.3_out_of_range + Scenario: Error when maxAge is out of range + Given the request body property "$.maxAge" is set to a value greater than the allowed range + When the HTTP "POST" request is sent + Then the response status code is 400 + And the response property "$.status" is 400 + And the response property "$.code" is "OUT_OF_RANGE" + And the response property "$.message" contains a user friendly text diff --git a/code/Test_definitions/retrieveDeviceSwapDate.feature b/code/Test_definitions/retrieveDeviceSwapDate.feature index 4e30659..f3adcc4 100644 --- a/code/Test_definitions/retrieveDeviceSwapDate.feature +++ b/code/Test_definitions/retrieveDeviceSwapDate.feature @@ -3,150 +3,148 @@ Feature: CAMARA Device Swap API, wip - Operation retrieveDeviceSwapDate # Input to be provided by the implementation to the tester # # Testing assets: + # * A device object which a device swap occured in the last 240 hours. # - # References to OAS spec schemas refer to schemas specifies in device-swap.yaml, version wip - # - # Get timestamp of last device swap for a mobile user account provided with phone number. - - Background: Common retrieveDeviceSwapDate setup - Given the resource "device-swap/vwip/retrieve-date" - And the header "Content-Type" is set to "application/json" - And the header "Authorization" is set to a valid access token - And the header "x-correlator" complies with the schema at "#/components/schemas/XCorrelator" - And the request body is set by default to a request body compliant with the schema - - # This first scenario serves as a minimum, not testing any specific verificationResult - @retrieve_device_swap_date_1_generic_success_scenario - Scenario: Common validations for any sucess scenario - Given a valid phone number identified by the token or provided in the request body - When the request "retrieveDeviceSwapDate" is sent - Then the response status code is 200 - And the response header "Content-Type" is "application/json" - And the response header "x-correlator" has same value as the request header "x-correlator" - And the response body complies with the OAS schema at "/components/schemas/DeviceSwapInfo" - - # Scenarios testing specific situations - - @retrieve_device_swap_date_2_valid_device_swap - Scenario: Retrieve decive swap date for a valid device swap - Given a valid phone number identified by the token or provided in the request body - And the device has been swapped - When the request "retrieveDeviceSwapDate" is sent - Then the response status code is 200 - And the response property "$.latestDeviceChange" contains a valid timestamp - - # This scenario applies for operators which do not limit the "monitoring history" - @retrieve_device_swap_date_3_no_device_swap_returns_activation_date - Scenario: Response contains the first time that the SIM is installed in the device when it hasn't been swapped - Given a valid phone number identified by the token or provided in the request body - And the device has never been swapped - When the request "retrieveDeviceSwapDate" is sent - Then the response status code is 200 - And the response property "$.latestDeviceChange" contains the timestamp of the first time that the SIM is installed in the device - - - # This scenario applies when there is a local regulation with a time limitation on the information that can be returned - @retrieve_device_swap_date_4_no_device_swap_or_activation_date_due_to_legal_constrain - Scenario: Retrieves device swap empty for a valid device swap when exists local regulations - Given a valid phone number identified by the token or provided in the request body - And the last device swap occurred outside the monitoring period allowed by local regulation - When the request "retrieveDeviceSwapDate" is sent - Then the response status code is 200 - And the response property "$.latestDeviceChange" is null - - # Specific errors - - # This test applies if the operator allows to do the request for a sim that has never been connected to the network - @retrieve_device_swap_date_5_not_activated - Scenario: Error device swap date for a non-activated sim - Given a valid phone number provided in the request body - And the sim for that device has never been connected to the Operator's network - When the HTTP "POST" request is sent - Then the response status code is 422 - And the response property "$.status" is 422 - And the response property "$.code" is "SERVICE_NOT_APPLICABLE" - And the response property "$.message" contains a user friendly text - - # Test cases related to the device identifier - - @retrieve_device_swap_date_6_C02_01_phone_number_not_schema_compliant - Scenario: Phone number value does not comply with the schema - Given the header "Authorization" is set to a valid access token which does not identify a single phone number - And the request body property "$.phoneNumber" does not comply with the OAS schema at "/components/schemas/PhoneNumber" - When the HTTP "POST" request is sent - Then the response status code is 400 - And the response property "$.status" is 400 - And the response property "$.code" is "INVALID_ARGUMENT" - And the response property "$.message" contains a user friendly text - - @retrieve_device_swap_date_7_C02_02_phone_number_not_found - Scenario: Phone number not found - Given the header "Authorization" is set to a valid access token which does not identify a single phone number - And the request body property "$.phoneNumber" is compliant with the schema but does not identify a valid phone number - When the HTTP "POST" request is sent - Then the response status code is 404 - And the response property "$.status" is 404 - And the response property "$.code" is "IDENTIFIER_NOT_FOUND" - And the response property "$.message" contains a user friendly text - - @retrieve_device_swap_date_8_C02_03_unnecessary_phone_number - Scenario: Phone number not to be included when it can be deduced from the access token - Given the header "Authorization" is set to a valid access token identifying a phone number - And the request body property "$.phoneNumber" is set to a valid phone number - When the HTTP "POST" request is sent - Then the response status code is 422 - And the response property "$.status" is 422 - And the response property "$.code" is "UNNECESSARY_IDENTIFIER" - And the response property "$.message" contains a user friendly text - - @check_device_swap_9_C02_04_missing_phone_number - Scenario: Phone number not included and cannot be deducted from the access token - Given the header "Authorization" is set to a valid access token which does not identify a single phone number - And the request body property "$.phoneNumber" is not included - When the HTTP "POST" request is sent - Then the response status code is 422 - And the response property "$.status" is 422 - And the response property "$.code" is "MISSING_IDENTIFIER" - And the response property "$.message" contains a user friendly text - - @retrieve_device_swap_date_10_C02_05_phone_number_not_supported - Scenario: Service not available for the phone number - Given that the service is not available for all phone numbers commercialized by the operator - And a valid phone number, identified by the token or provided in the request body, for which the service is not applicable - When the HTTP "POST" request is sent - Then the response status code is 422 - And the response property "$.status" is 422 - And the response property "$.code" is "SERVICE_NOT_APPLICABLE" - And the response property "$.message" contains a user friendly text - - # Generic 401 errors - - @retrieve_device_swap_date_401.1_no_authorization_header - Scenario: No Authorization header - Given the header "Authorization" is removed - And the request body is set to a valid request body - When the HTTP "POST" request is sent - Then the response status code is 401 - And the response property "$.status" is 401 - And the response property "$.code" is "UNAUTHENTICATED" - And the response property "$.message" contains a user friendly text - - @retrieve_device_swap_date_401.2_expired_access_token - Scenario: Expired access token - Given the header "Authorization" is set to an expired access token - And the request body is set to a valid request body - When the HTTP "POST" request is sent - Then the response status code is 401 - And the response property "$.status" is 401 - And the response property "$.code" is "UNAUTHENTICATED" - And the response property "$.message" contains a user friendly text - - @retrieve_device_swap_date_401.3_invalid_access_token - Scenario: Invalid access token - Given the header "Authorization" is set to an invalid access token - And the request body is set to a valid request body - When the HTTP "POST" request is sent - Then the response status code is 401 - And the response property "$.status" is 401 - And the response property "$.code" is "UNAUTHENTICATED" - And the response property "$.message" contains a user friendly text + # References to OAS spec schemas refer to schemas specifies in device-swap.yaml. + + Background: Common retrieveDeviceSwapDate setup + Given the resource "device-swap/vwip/retrieve-date" + And the header "Content-Type" is set to "application/json" + And the header "Authorization" is set to a valid access token + And the header "x-correlator" complies with the schema at "#/components/schemas/XCorrelator" + And the request body is set by default to a request body compliant with the schema + + # This first scenario serves as a minimum, not testing any specific verificationResult + @retrieve_device_swap_date_1_generic_success_scenario + Scenario: Common validations for any sucess scenario + Given a valid phone number identified by the token or provided in the request body + When the request "retrieveDeviceSwapDate" is sent + Then the response status code is 200 + And the response header "Content-Type" is "application/json" + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response body complies with the OAS schema at "/components/schemas/DeviceSwapInfo" + + # Scenarios testing specific situations + + @retrieve_device_swap_date_2_valid_device_swap + Scenario: Retrieve decive swap date for a valid device swap + Given a valid phone number identified by the token or provided in the request body + And the device has been swapped + When the request "retrieveDeviceSwapDate" is sent + Then the response status code is 200 + And the response property "$.latestDeviceChange" contains a valid timestamp + + # This scenario applies for operators which do not limit the "monitoring history" + @retrieve_device_swap_date_3_no_device_swap_returns_activation_date + Scenario: Response contains the first time that the SIM is installed in the device when it hasn't been swapped + Given a valid phone number identified by the token or provided in the request body + And the device has never been swapped + When the request "retrieveDeviceSwapDate" is sent + Then the response status code is 200 + And the response property "$.latestDeviceChange" contains the timestamp of the first time that the SIM is installed in the device + + # This scenario applies when there is a local regulation with a time limitation on the information that can be returned + @retrieve_device_swap_date_4_no_device_swap_or_activation_date_due_to_legal_constrain + Scenario: Retrieves device swap empty for a valid device swap when exists local regulations + Given a valid phone number identified by the token or provided in the request body + And the last device swap occurred outside the monitoring period allowed by local regulation + When the request "retrieveDeviceSwapDate" is sent + Then the response status code is 200 + And the response property "$.latestDeviceChange" is null + + # Specific errors + + # This test applies if the operator allows to do the request for a sim that has never been connected to the network + @retrieve_device_swap_date_5_not_activated + Scenario: Error device swap date for a non-activated sim + Given a valid phone number provided in the request body + And the sim for that device has never been connected to the Operator's network + When the HTTP "POST" request is sent + Then the response status code is 422 + And the response property "$.status" is 422 + And the response property "$.code" is "SERVICE_NOT_APPLICABLE" + And the response property "$.message" contains a user friendly text + + # Test cases related to the device identifier + + @retrieve_device_swap_date_6_C02_01_phone_number_not_schema_compliant + Scenario: Phone number value does not comply with the schema + Given the header "Authorization" is set to a valid access token which does not identify a single phone number + And the request body property "$.phoneNumber" does not comply with the OAS schema at "/components/schemas/PhoneNumber" + When the HTTP "POST" request is sent + Then the response status code is 400 + And the response property "$.status" is 400 + And the response property "$.code" is "INVALID_ARGUMENT" + And the response property "$.message" contains a user friendly text + + @retrieve_device_swap_date_7_C02_02_phone_number_not_found + Scenario: Phone number not found + Given the header "Authorization" is set to a valid access token which does not identify a single phone number + And the request body property "$.phoneNumber" is compliant with the schema but does not identify a valid phone number + When the HTTP "POST" request is sent + Then the response status code is 404 + And the response property "$.status" is 404 + And the response property "$.code" is "IDENTIFIER_NOT_FOUND" + And the response property "$.message" contains a user friendly text + + @retrieve_device_swap_date_8_C02_03_unnecessary_phone_number + Scenario: Phone number not to be included when it can be deduced from the access token + Given the header "Authorization" is set to a valid access token identifying a phone number + And the request body property "$.phoneNumber" is set to a valid phone number + When the HTTP "POST" request is sent + Then the response status code is 422 + And the response property "$.status" is 422 + And the response property "$.code" is "UNNECESSARY_IDENTIFIER" + And the response property "$.message" contains a user friendly text + + @check_device_swap_9_C02_04_missing_phone_number + Scenario: Phone number not included and cannot be deducted from the access token + Given the header "Authorization" is set to a valid access token which does not identify a single phone number + And the request body property "$.phoneNumber" is not included + When the HTTP "POST" request is sent + Then the response status code is 422 + And the response property "$.status" is 422 + And the response property "$.code" is "MISSING_IDENTIFIER" + And the response property "$.message" contains a user friendly text + + @retrieve_device_swap_date_10_C02_05_phone_number_not_supported + Scenario: Service not available for the phone number + Given that the service is not available for all phone numbers commercialized by the operator + And a valid phone number, identified by the token or provided in the request body, for which the service is not applicable + When the HTTP "POST" request is sent + Then the response status code is 422 + And the response property "$.status" is 422 + And the response property "$.code" is "SERVICE_NOT_APPLICABLE" + And the response property "$.message" contains a user friendly text + + # Generic 401 errors + + @retrieve_device_swap_date_401.1_no_authorization_header + Scenario: No Authorization header + Given the header "Authorization" is removed + And the request body is set to a valid request body + When the HTTP "POST" request is sent + Then the response status code is 401 + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" + And the response property "$.message" contains a user friendly text + + @retrieve_device_swap_date_401.2_expired_access_token + Scenario: Expired access token + Given the header "Authorization" is set to an expired access token + And the request body is set to a valid request body + When the HTTP "POST" request is sent + Then the response status code is 401 + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" + And the response property "$.message" contains a user friendly text + + @retrieve_device_swap_date_401.3_invalid_access_token + Scenario: Invalid access token + Given the header "Authorization" is set to an invalid access token + And the request body is set to a valid request body + When the HTTP "POST" request is sent + Then the response status code is 401 + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" + And the response property "$.message" contains a user friendly text