diff --git a/code/API_definitions/connected-network-type-subscriptions.yaml b/code/API_definitions/connected-network-type-subscriptions.yaml index 264c9fd6..d300f008 100644 --- a/code/API_definitions/connected-network-type-subscriptions.yaml +++ b/code/API_definitions/connected-network-type-subscriptions.yaml @@ -1336,7 +1336,6 @@ components: - MISSING_IDENTIFIER - UNSUPPORTED_IDENTIFIER - UNNECESSARY_IDENTIFIER - - MULTIEVENT_SUBSCRIPTION_NOT_SUPPORTED examples: GENERIC_422_IDENTIFIER_MISMATCH: description: Inconsistency between identifiers not pointing to the same device diff --git a/code/Test_definitions/connected-network-type-subscriptions.feature b/code/Test_definitions/connected-network-type-subscriptions.feature index 628f7b2c..251233b9 100644 --- a/code/Test_definitions/connected-network-type-subscriptions.feature +++ b/code/Test_definitions/connected-network-type-subscriptions.feature @@ -1,289 +1,548 @@ -@Connected_network_type_subscription -Feature: CAMARA Connected Network Type Subscriptions API, vwip - Operations on subscriptions +@Connected_Network_Type_Subscription +Feature: CAMARA Connected Network Type Subscriptions API, vwip - Operations createConnectedNetworkTypeSubscription, retrieveConnectedNetworkTypeSubscriptionList, retrieveConnectedNetworkTypeSubscription and deleteConnectedNetworkTypeSubscription -# Input to be provided by the implementation to the tests -# References to OAS spec schemas refer to schemas specifies in connected-network-type-subscriptions.yaml + # Input to be provided by the implementation to the tester + # + # Implementation indications: + # * List of device identifier types which are not supported, among: phoneNumber, networkAccessIdentifier, ipv4Address, ipv6Address + # + # Testing assets: + # * A device object where the tester can select between multiple network types. + # * (optional: Additional devices object which supports 2G, 3G, 4G and/or 5G) + # * The known connected Generation of Mobile Communication Technology. + # * A sink-url identified as "callbackUrl", which receives notifications + # + # References to OAS spec schemas refer to schemas specifies in connected-network-type-subscriptions.yaml Background: Connected Network Type Subscriptions setup Given the resource "{apiroot}/connected-network-type-subscriptions/vwip" as base-url And the header "Authorization" is set to a valid access token And the header "x-correlator" is set to a UUID value -######### Happy Path Scenarios ################################# +########################## +# Happy path scenarios +########################## - @connected_network_type_subscriptions_01_create_connected_network_type_subscription_sync - Scenario: Create connected network type subscription synchronously - Given that subscriptions are created synchronously - And a valid subscription request body + @connected_network_type_subscriptions_01.1_sync_creation_2legs + Scenario Outline: Synchronous subscription creation with 2-legged-access-token + # Some implementations may only support asynchronous subscription creation + Given the header "Authorization" is set to a valid access token which does not identify any device When the request "createConnectedNetworkTypeSubscription" is sent - Then the response code is 201 + And request property "$.types" is one of the allowed values "" + And request property "$.protocol" is equal to "HTTP" + And a valid phone number identified by "$.config.subscriptionDetail.device.phoneNumber" + And request property "$.sink" is set to a valid callbackUrl + Then the response status code is 201 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/Subscription" + And the response body complies with the OAS schema at "#/components/schemas/Subscription" + And the response properties "$.types", "$.protocol", "$.sink" and "$.config.subscriptionDetail.device.phoneNumber" are present with the values provided in the request + And the response property "$.id" is present + And the response property "$.startsAt", if present, has a valid value with date-time format + And the response property "$.expiresAt", if present, has a valid value with date-time format + And the response property "$.status", if present, has the value "ACTIVATION_REQUESTED", "ACTIVE" or "INACTIVE" - @connected_network_type_subscriptions_02_create_connected_network_type_subscription_async - Scenario: Create connected network type subscription asynchronously - Given that subscriptions are created asynchronously - And a valid subscription request body + Examples: + | subscription-creation-types | + | org.camaraproject.connected-network-type-subscriptions.v0.network-type-changed | + + @connected_network_type_subscriptions_01.2_sync_creation_3legs + Scenario Outline: Synchronous subscription creation with 3-legged-access-token + # Some implementations may only support asynchronous subscription creation + Given the header "Authorization" is set to a valid access token which identifies a valid device + When the request "createConnectedNetworkTypeSubscription" is sent + And request property "$.types" is one of the allowed values "" + And request property "$.protocol" is equal to "HTTP" + And request property "$.sink" is set to a valid callbackUrl + And request property "$.config.subscriptionDetail.device.phoneNumber" is not present + Then the response status code is 201 + 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/Subscription" + And the response properties "$.types", "$.protocol" and "$.sink" are present with the values provided in the request + And the response property "$.id" is present + And the response property "$.startsAt", if present, has a valid value with date-time format + And the response property "$.expiresAt", if present, has a valid value with date-time format + And the response property "$.status", if present, has the value "ACTIVATION_REQUESTED", "ACTIVE" or "INACTIVE" + And the response property "$.config.subscriptionDetail.device" is not present + + Examples: + | subscription-creation-types | + | org.camaraproject.connected-network-type-subscriptions.v0.network-type-changed | + + @connected_network_type_subscriptions_02_async_creation + Scenario Outline: Asynchronous subscription creation with 2- or 3-legged access token + # Some implementations may only support synchronous subscription creation + Given a valid target device, identified by either the access token or in the request body When the request "createConnectedNetworkTypeSubscription" is sent - Then the response code is 202 + And request property "$.types" is one of the allowed values "" + And request property "$.protocol" is equal to "HTTP" + And request property "$.sink" is set to a valid callbackUrl + Then the response status code is 202 + 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/SubscriptionAsync" + And the response property "$.id" is present + + Examples: + | subscription-creation-types | + | org.camaraproject.connected-network-type-subscriptions.v0.network-type-changed | + + @connected_network_type_subscriptions_03.1_retrieve_by_id_2legs + Scenario: Check existing subscription is retrieved by id with a 2-legged access token + Given a subscription exists and has a subscriptionId equal to "id" + And the header "Authorization" is set to a valid access token which does not identify any device + When the request "retrieveConnectedNetworkTypeSubscription" is sent + And the path parameter "subscriptionId" is set to "id" + 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/SubscriptionAsync" + And the response body complies with the OAS schema at "#/components/schemas/Subscription" + And the response property "$.id" is equal to "id" + And the response property "$.config.subscriptionDetail.device" is present - @connected_network_type_subscriptions_03_operation_to_retrieve_list_of_subscriptions_when_no_records - Scenario: Get a list of subscriptions when no subscriptions available - Given a client without subscriptions created + @connected_network_type_subscriptions_03.2_retrieve_by_id_3legs + Scenario: Check existing subscription is retrieved by id with a 3-legged access token + Given a subscription exists and has a subscriptionId equal to "id" + And the header "Authorization" is set to a valid access token which identifies the device associated with the subscription + When the request "retrieveConnectedNetworkTypeSubscription" + And the path parameter "subscriptionId" is set to "id" + 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/Subscription" + And the response property "$.id" is equal to "id" + And the response property "$.config.subscriptionDetail.device" is not present + + @connected_network_type_subscriptions_04_retrieve_list_2legs + Scenario: Check existing subscription(s) is/are retrieved in list + Given at least one subscription is existing for the API consumer making this request + And the header "Authorization" is set to a valid access token which does not identify any device When the request "retrieveConnectedNetworkTypeSubscriptionList" is sent - Then the response code is 200 + 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 is an empty array + And the response body complies with an array of OAS schema defined at "#/components/schemas/Subscription" + And the response body lists all subscriptions belonging to the API consumer - @connected_network_type_subscriptions_04_operation_to_retrieve_list_of_subscriptions - Scenario: Get a list of subscriptions - Given a client with subscriptions created + @connected_network_type_subscriptions_05_retrieve_list_3legs + Scenario: Check existing subscription(s) is/are retrieved in list + Given the API consumer has at least one active subscription for the device + And the header "Authorization" is set to a valid access token which identifies a valid device associated with one or more subscriptions When the request "retrieveConnectedNetworkTypeSubscriptionList" is sent - Then the response code is 200 + 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 has an array of items and each item complies with the OAS schema at "/components/schemas/Subscription" + And the response body complies with an array of OAS schema defined at "#/components/schemas/Subscription" + And the response body lists all subscriptions belonging to the API consumer for the identified device + And the response property "$.config.subscriptionDetail.device" is not present in any of the subscription records - @connected_network_type_subscriptions_05_operation_to_retrieve_subscription_based_on_an_existing_subscription-id - Scenario: Get a subscription based on existing subscription-id. - Given the path parameter "subscriptionId" is set to the identifier of an existing subscription - When the request "retrieveConnectedNetworkTypeSubscription" is sent - Then the response code is 200 + @connected_network_type_subscriptions_06_retrieve_empty_list_3legs + Scenario: Check no existing subscription is retrieved in list + Given the API consumer has no active subscriptions for the device + And the header "Authorization" is set to a valid access token which identifies a valid device + When the request "retrieveConnectedNetworkTypeSubscriptionList" 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/Subscription" + And the response body is an empty array - @connected_network_type_subscriptions_06_operation_to_delete_subscription_based_on_an_existing_subscription-id - Scenario: Delete a subscription based on existing subscription-id. - Given the path parameter "subscriptionId" is set to the identifier of an existing subscription + @connected_network_type_subscriptions_07_delete_subscription_based_on_an_existing_subscription-id + Scenario: Delete the subscription with subscriptionId equal to "id" + Given the API consumer has an active subscription with "subscriptionId" equal to "id" When the request "deleteConnectedNetworkTypeSubscription" is sent - Then the response code is 202 or 204 + And the path parameter "subscriptionId" is set to "id" + Then the response status code is 202 or 204 And the response header "x-correlator" has same value as the request header "x-correlator" - And if the response property $.status is 204 then response body is not available - And if the response property $.status is 202 then response body complies with the OAS schema at "/components/schemas/SubscriptionAsync" + And if the response property "$.status" is 204 then response body is not present + And if the response property "$.status" is 202 then response body complies with the OAS schema at "#/components/schemas/SubscriptionAsync" and the response property "$.id" is equal to "id" - @connected_network_type_subscriptions_07_receive_notification_when_network_type_changed + @connected_network_type_subscriptions_08_receive_notification_when_network_type_changed Scenario: Receive notification for network-type-changed event - Given that subscriptions are created synchronously - And a valid subscription request body - And the request body property "$.types" contains the element "network-type-changed" - When the request "createConnectedNetworkTypeSubscription" is sent - Then the response code is 201 - And if the device network type changed - Then event notification "network-type-changed" is received on callback-url - And sink credentials are received as expected + Given a valid subscription for a device exists with "subscriptionId" equal to "id" + And the subscription property "$.types" contains the element "org.camaraproject.connected-network-type-subscriptions.v0.network-type-changed" + And the subscription property "$.sink" is a valid callback URL + When the network type the device is connected to changes + Then event notification "network-type-changed" is sent to the specified callback URL + And the sink credentials specified when the subscription was created are included And notification body complies with the OAS schema at "#/components/schemas/EventNetworkTypeChange" - And type="org.camaraproject.connected-network-type-subscriptions.v0.network-type-changed" + And the notification property "$.type" is equal to "org.camaraproject.connected-network-type-subscriptions.v0.network-type-changed" + And the notification property "$.data.subscriptionId" is equal to "id" - @connected_network_type_subscriptions_08_subscription_ends_on_expiry + @connected_network_type_subscriptions_09_subscription_expiry Scenario: Receive notification for subscription-ends event on expiry - Given that subscriptions are created synchronously - And a valid subscription request body - And the request body property "$.subscriptionExpireTime" is set to a value in the near future - When the request "createConnectedNetworkTypeSubscription" is sent - Then the response code is 201 - Then the subscription is expired - Then event notification "subscription-ends" is received on callback-url - And notification body complies with the OAS schema at "#/components/schemas/EventSubscriptionEnds" - And type="org.camaraproject.connected-network-type-subscriptions.v0.subscription-ends" - And the response property "$.terminationReason" is "SUBSCRIPTION_EXPIRED" - - @connected_network_type_subscriptions_09_subscription_end_when_max_events + Given a valid subscription for a device exists with "subscriptionId" equal to "id" + And the subscription property "$.subscriptionExpireTime" is set to a value in the near future + And the subscription property "$.sink" is a valid callback URL + When the subscriptionExpireTime is reached + Then a subscription termination event notification is sent to the callback URL + And the notification body complies with the OAS schema at "#/components/schemas/EventSubscriptionEnds" + And the notification property "$.type" is "org.camaraproject.connected-network-type-subscriptions.v0.subscription-ends" + And the notification property "$.data.subscriptionId" is equal to "id" + And the notification property "$.data.terminationReason" is equal to "SUBSCRIPTION_EXPIRED" + + @connected_network_type_subscriptions_10_subscription_end_when_max_events Scenario: Receive notification for subscription-ends event on max events reached - Given that subscriptions are created synchronously - And a valid subscription request body - And the request body property "$.types" contains the element "network-type-changed" - And the request body property "$.subscriptionMaxEvents" is set to 1 - When the request "createConnectedNetworkTypeSubscription" is sent - Then the response code is 201 - Then event notification "network-type-changed" is received on callback-url - Then event notification "subscription-ends" is received on callback-url - And notification body complies with the OAS schema at "##/components/schemas/EventSubscriptionEnds" - And type="org.camaraproject.connected-network-type-subscriptions.v0.subscription-ends" - And the response property "$.terminationReason" is "MAX_EVENTS_REACHED" - - @connected_network_type_subscriptions_10_subscription_delete_event_validation + Given a valid subscription for a device exists with "subscriptionId" equal to "id" + And the subscription property "$.subscriptionMaxEvents" is set to 1 + And the subscription property "$.sink" is a valid callback URL + When a single notification corresponding to subscription property "$.type" has been sent to the callback URL + Then a subscription termination event notification is sent to the callback URL + And the notification body complies with the OAS schema at "#/components/schemas/EventSubscriptionEnds" + And the notification property "$.type" is equal to "org.camaraproject.connected-network-type-subscriptions.v0.subscription-ends" + And the notification property "$.data.subscriptionId" is equal to "id" + And the notification request property "$.data.terminationReason" is equal to "MAX_EVENTS_REACHED" + + @connected_network_type_subscriptions_11_subscription_delete_event_validation Scenario: Receive notification for subscription-ends event on deletion - Given that subscriptions are created synchronously - And a valid subscription request body + Given a valid subscription for a device exists with "subscriptionId" equal to "id" + And the subscription property "$.sink" is a valid callback URL + When the request "deleteConnectedNetworkTypeSubscription" is sent + And the path parameter "subscriptionId" is set to "id" + And the response status code is 202 or 204 + Then a subscription termination event notification is sent to the callback URL + And the notification body complies with the OAS schema at "#/components/schemas/EventSubscriptionEnds" + And the notification property "$.type" is equal to "org.camaraproject.connected-network-type-subscriptions.v0.subscription-ends" + And the notification property "$.data.subscriptionId" is equal to "id" + And the notification request property "$.data.terminationReason" is equal to "SUBSCRIPTION_DELETED" + +################ +# Error scenarios for management of input parameter device +################## + + @connected_network_type_subscriptions_C01.01_device_empty + Scenario: The device value is an empty object + Given the header "Authorization" is set to a valid access token which does not identify a single device + And the request body property "$.device" is set to: {} When the request "createConnectedNetworkTypeSubscription" is sent - Then the response code is 201 - When the request "deleteSubscription" is sent - Then the response code is 202 or 204 - Then event notification "subscription-ends" is received on callback-url - And notification body complies with the OAS schema at "##/components/schemas/EventSubscriptionEnds" - And type="org.camaraproject.connected-network-type-subscriptions.v0.subscription-ends" - And the response property "$.terminationReason" is "SUBSCRIPTION_DELETED" + 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 -############### Error response scenarios ########################### + @connected_network_type_subscriptions_C01.02_device_identifiers_not_schema_compliant + Scenario Outline: Some device identifier value does not comply with the schema + Given the header "Authorization" is set to a valid access token which does not identify a single device + And the request body property "" does not comply with the OAS schema at "" + When the request "createConnectedNetworkTypeSubscription" 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 - @connected_network_type_subscriptions_11_create_network_type_subscription_with_invalid_parameter + Examples: + | device_identifier | oas_spec_schema | + | $.device.phoneNumber | /components/schemas/PhoneNumber | + | $.device.ipv4Address | /components/schemas/DeviceIpv4Addr | + | $.device.ipv6Address | /components/schemas/DeviceIpv6Address | + | $.device.networkIdentifier | /components/schemas/NetworkAccessIdentifier | + + # This scenario may happen e.g. with 2-legged access tokens, which do not identify a single device. + @connected_network_type_subscriptions_C01.03_device_not_found + Scenario: Some identifier cannot be matched to a device + Given the header "Authorization" is set to a valid access token which does not identify a single device + And the request body property "$.device" is compliant with the schema but does not identify a device whose connectivity is managed by the API provider + When the request "createConnectedNetworkTypeSubscription" 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 + + @connected_network_type_subscriptions_C01.04_unnecessary_device + Scenario: Device 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 device + And the request body property "$.device" is also set to a valid device, which may or may not be the same device + When the request "createConnectedNetworkTypeSubscription" 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 + + @connected_network_type_subscriptions_C01.05_missing_device + Scenario: Device not included and cannot be deduced from the access token + Given the header "Authorization" is set to a valid access token which does not identify a single device + And the request body property "$.device" is not included + When the request "createConnectedNetworkTypeSubscription" 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 + + @connected_network_type_subscriptions_C01.06_unsupported_device + Scenario: None of the provided device identifiers is supported by the implementation + Given that some types of device identifiers are not supported by the implementation + And the header "Authorization" is set to a valid access token which does not identify a single device + And the request body property "$.device" only includes device identifiers not supported by the implementation + When the request "createConnectedNetworkTypeSubscription" is sent + Then the response status code is 422 + And the response property "$.status" is 422 + And the response property "$.code" is "UNSUPPORTED_IDENTIFIER" + And the response property "$.message" contains a user-friendly text + + # When the service is only offered to certain types of devices or subscriptions, e.g. IoT, B2C, etc. + @connected_network_type_subscriptions_C01.07_device_not_supported + Scenario: Service not available for the device + Given that the service is not available for all devices commercialized by the operator + And a valid device, identified by the token or provided in the request body, for which the service is not applicable + When the request "createConnectedNetworkTypeSubscription" 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 + + # Several identifiers provided but they do not identify the same device + # This scenario may happen with 2-legged access tokens, which do not identify a device + @connected_network_type_subscriptions_C01.08_device_identifiers_mismatch + Scenario: Device identifiers mismatch + Given the header "Authorization" is set to a valid access token which does not identify a single device + And at least 2 types of device identifiers are supported by the implementation + And the request body property "$.device" includes several identifiers, each of them identifying a valid but different device + When the request "createConnectedNetworkTypeSubscription" is sent + Then the response status code is 422 + And the response property "$.status" is 422 + And the response property "$.code" is "IDENTIFIER_MISMATCH" + And the response property "$.message" contains a user friendly text + +################## +# Error code 400 +################## + + @connected_network_type_subscriptions_400.1_create_subscription_with_invalid_parameter Scenario: Create subscription with invalid parameter - Given the request body is not compliant with the schema "/components/schemas/SubscriptionRequest" + Given the request body is not compliant with the schema "#/components/schemas/SubscriptionRequest" When the request "createConnectedNetworkTypeSubscription" is sent - Then the response code is 400 + 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 - @connected_network_type_subscriptions_12_creation_of_subscription_with_expiry_time_in_past + @connected_network_type_subscriptions_400.2_create_subscription_with_invalid_subscription_expire_time Scenario: Expiry time in past - Given a valid subscription request body - And request body property "$.subscriptionexpiretime" in past + Given the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" + And the request property "$.config.subscriptionExpireTime" is set to a time in the past When the request "createConnectedNetworkTypeSubscription" is sent - Then the response code is 400 + 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 - @connected_network_type_subscriptions_13_invalid_eventType + @connected_network_type_subscriptions_400.3_invalid_eventType Scenario: Subscription creation with invalid event type - Given a valid subscription request body - And the request body property "$.types" is set to invalid value + Given the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" + And the request body property "$.types" is set to a value other than "org.camaraproject.connected-network-type-subscriptions.v0.network-type-changed" When the request "createConnectedNetworkTypeSubscription" is sent - Then the response code is 400 - and the response property "$.status" is 400 + 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 - @connected_network_type_subscriptions_14_invalid_protocol + @connected_network_type_subscriptions_400.4_invalid_protocol Scenario: subscription creation with invalid protocol - Given a valid subscription request body - And the request property "$.protocol" is not set to "HTTP" + Given the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" + And the request property "$.protocol" is not equal to "HTTP" When the request "createConnectedNetworkTypeSubscription" is sent - Then the response code is 400 + Then the response status code is 400 And the response property "$.status" is 400 And the response property "$.code" is "INVALID_PROTOCOL" And the response property "$.message" contains a user friendly text - @connected_network_type_subscriptions_15_invalid_credential + @connected_network_type_subscriptions_400.5_create_subscription_with_invalid_credential_type Scenario: subscription creation with invalid credential type - Given a valid subscription request body - And the request property "$.credentialType" is not "ACCESSTOKEN" + Given the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" + And the request property "$.sinkCredential.accessTokenType" is equal to "bearer" + And the request property "$.sinkCredential.credentialType" is not equal to "ACCESSTOKEN" When the request "createConnectedNetworkTypeSubscription" is sent - Then the response code is 400 + Then the response status code is 400 And the response property "$.status" is 400 And the response property "$.code" is "INVALID_CREDENTIAL" And the response property "$.message" contains a user friendly text - @connected_network_type_subscriptions_16_invalid_access_token_type - Scenario: subscription creation with invalid access token type - Given a valid subscription request body - And the request property "$.accessTokenType" is not "bearer" + @connected_network_type_subscriptions_400.6_create_subscription_with_invalid_access_token_type + Scenario: subscription creation with invalid token + Given the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" + And the request property "$.sinkCredential.credentialType" is equal to "ACCESSTOKEN" + And the request property "$.sinkCredential.accessTokenType" is not equal to "bearer" When the request "createConnectedNetworkTypeSubscription" is sent - Then the response code is 400 + Then the response status code is 400 And the response property "$.status" is 400 - And the response property "$.code" is "INVALID_TOKEN" or "INVALID_ARGUMENT" + And the response property "$.code" is "INVALID_TOKEN" And the response property "$.message" contains a user friendly text - @connected_network_type_subscriptions_17_no_authorization_header_for_create_subscription - Scenario: subscription creation with invalid credentials - Given a valid subscription request body - And header "Authorization" token is set to invalid credentials +################## +# Error code 401 +################## + + @connected_network_type_subscriptions_creation_401.1_no_authorization_header + Scenario: No Authorization header + Given the request header "Authorization" is removed + And the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" When the request "createConnectedNetworkTypeSubscription" is sent - Then the response code is 401 + Then the response status code is 401 + And the response header "Content-Type" is "application/json" And the response property "$.status" is 401 - And the response property "$.code" is "UNAUTHENTICATED" + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" And the response property "$.message" contains a user friendly text - @connected_network_type_subscriptions_18_expired_access_token_for_create_subscription - Scenario: Expired access token for create subscription - Given a valid subscription request body and header "Authorization" is expired + @connected_network_type_subscriptions_creation_401.2_expired_access_token + Scenario: Expired access token + Given the header "Authorization" is set to a previously valid but now expired access token + And the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" When the request "createConnectedNetworkTypeSubscription" is sent Then the response status code is 401 + And the response header "Content-Type" is "application/json" And the response property "$.status" is 401 - And the response property "$.code" is "UNAUTHENTICATED" + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" And the response property "$.message" contains a user friendly text - @connected_network_type_subscriptions_19_permission_denied - Scenario: subscription creation with inconsistent access token for requested events subscription - # To test this, a token does not have the required scope - Given a valid subscription request body - And the request body property "$.device" is set to a valid testing device supported by the service - And header "Authorization" set to access token referring different scope + @connected_network_type_subscriptions_creation_401.3_malformed_access_token + Scenario: Malformed access token + Given the header "Authorization" is set to a malformed token + And the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" When the request "createConnectedNetworkTypeSubscription" is sent - Then the response property "$.status" is 403 - And the response property "$.code" is "PERMISSION_DENIED" + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" And the response property "$.message" contains a user friendly text - @connected_network_type_subscriptions_20_unnecessary_identifier - Scenario: subscription creation with both a 3-legged token and explicit device identifier - # This test applies whether the device associated with the access token matches the explicit device identifier or not - # For 3-legged access tokens, an explicit device identifier MUST NOT be provided - Given a valid subscription request body - And the request body property "$.device" is set to a valid testing device supported by the service - And header "Authorization" set to access token also referring to a device (which may or may not be the same device) - When the request "createConnectedNetworkTypeSubscription" is sent - Then the response property "$.status" is 422 - And the response property "$.code" is "UNNECESSARY_IDENTIFIER" + @connected_network_type_subscriptions_retrieve_401.4_no_authorization_header + Scenario: No Authorization header + Given the request header "Authorization" is removed + When the request "retrieveConnectedNetworkTypeSubscription" is sent + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" And the response property "$.message" contains a user friendly text - @connected_network_type_subscriptions_21_inconsistent_access_token_for_requested_events_subscription - Scenario: subscription creation with invalid access token for requested events subscription - # To test this, a token contains an unsupported event type for this API - Given a valid subscription request body - And the request body property "$.device" is set to a valid testing device supported by the service - And the request body property "$.types" contains the supported event type in this API - When the request "createConnectedNetworkTypeSubscription" is sent - Then the response property "$.status" is 403 - And the response property "$.code" is "SUBSCRIPTION_MISMATCH" + @connected_network_type_subscriptions_retrieve_401.5_expired_access_token + Scenario: Expired access token + Given the header "Authorization" is set to a previously valid but now expired access token + When the request "retrieveConnectedNetworkTypeSubscription" is sent + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" And the response property "$.message" contains a user friendly text - @connected_network_type_subscriptions_22_unknown_subscription_id - Scenario: Get subscription when subscription-id is unknown to the system - Given the path parameter property "$.subscriptionId" is unknown to the system + @connected_network_type_subscriptions_retrieve_401.6_malformed_access_token + Scenario: Malformed access token + Given the header "Authorization" is set to a malformed token When the request "retrieveConnectedNetworkTypeSubscription" is sent - Then the response code is 404 - And the response property "$.status" is 404 - And the response property "$.code" is "NOT_FOUND" + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" And the response property "$.message" contains a user friendly text - @connected_network_type_subscriptions_23_delete_unknown_subscription_id - Scenario: Delete subscription with subscription-id unknown to the system - Given the path parameter "subscriptionId" is set to the value unknown to system + @connected_network_type_subscriptions_delete_401.7_no_authorization_header + Scenario: No Authorization header + Given the request header "Authorization" is removed When the request "deleteConnectedNetworkTypeSubscription" is sent - Then the response code is 404 - And the response property "$.status" is 404 - And the response property "$.code" is "NOT_FOUND" + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" And the response property "$.message" contains a user friendly text - @connected_network_type_subscriptions_24_create_with_identifier_mismatch - Scenario: Create subscription with identifier mismatch - Given the request body includes inconsistent identifiers - When the request "createConnectedNetworkTypeSubscription" is sent - Then the response status code is 422 - And the response property "$.status" is 422 - And the response property "$.code" is "IDENTIFIER_MISMATCH" + @connected_network_type_subscriptions_delete_401.8_expired_access_token + Scenario: Expired access token + Given the header "Authorization" is set to a previously valid but now expired access token + When the request "deleteConnectedNetworkTypeSubscription" is sent + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" And the response property "$.message" contains a user friendly text - @connected_network_type_subscriptions_25_create_with_service_not_applicable - Scenario: Create subscription for a device not supported by the service - Given the request body includes a device identifier not applicable for this service - When the request "createConnectedNetworkTypeSubscription" 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" + @connected_network_type_subscriptions_delete_401.9_malformed_access_token + Scenario: Malformed access token + Given the header "Authorization" is set to a malformed token + When the request "deleteConnectedNetworkTypeSubscription" is sent + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" + And the response property "$.message" contains a user friendly text + + @connected_network_type_subscriptions_retrieve__list_401.10_no_authorization_header + Scenario: No Authorization header + Given the request header "Authorization" is removed + When the request "retrieveConnectedNetworkTypeSubscriptionList" is sent + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" And the response property "$.message" contains a user friendly text - @connected_network_type_subscriptions_26_create_with_unsupported_identifier - Scenario: Create subscription with an unsupported identifier - Given the request body includes an identifier type not supported by the implementation + @connected_network_type_subscriptions_retrieve_list_401.11_expired_access_token + Scenario: Expired access token + Given the header "Authorization" is set to a previously valid but now expired access token + When the request "retrieveConnectedNetworkTypeSubscriptionList" is sent + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" + And the response property "$.message" contains a user friendly text + + @connected_network_type_subscriptions_retrieve_list_401.12_malformed_access_token + Scenario: Malformed access token + Given the header "Authorization" is set to a malformed token + When the request "retrieveConnectedNetworkTypeSubscriptionList" is sent + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" + And the response property "$.message" contains a user friendly text + +################## +# Error code 403 +################## + + @connected_network_type_subscriptions_create_403.1_permission_denied + Scenario: subscription creation without having the required scope + # To test this, a token must not have the required scope + Given the header "Authorization" set to an access token not including scope "connected-network-type-subscriptions:org.camaraproject.connected-network-type-subscriptions.v0.network-type-changed:create" + And the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" + And the request body property "$.types" is equal to "org.camaraproject.connected-network-type-subscriptions.v0.network-type-changed" When the request "createConnectedNetworkTypeSubscription" is sent - Then the response status code is 422 - And the response property "$.status" is 422 - And the response property "$.code" is "UNSUPPORTED_IDENTIFIER" + Then the response status code is 403 + And the response property "$.status" is 403 + And the response property "$.code" is "PERMISSION_DENIED" And the response property "$.message" contains a user friendly text - @connected_network_type_subscriptions_27_missing_identifier - Scenario: Create subscription and identifier is not included in the request and the device or phone number identification cannot be derived from the 3-legged access token - Given the request body and identifier is not included and missing in the access token + @connected_network_type_subscriptions_create_403.2_subscription_mismatch_for_requested_events_subscription + Scenario: Subscription creation with invalid access token for requested events subscription + # Note - currently "org.camaraproject.connected-network-type-subscriptions.v0.network-type-changed" is the only valid subscription type for this API + Given the header "Authorization" set to an access token that includes only a single subscription scope + And the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" + And the request body property "$.types" is equal to a valid type other than the event corresponding to the access token scope When the request "createConnectedNetworkTypeSubscription" is sent - Then the response status code is 422 - And the response property "$.status" is 422 - And the response property "$.code" is "MISSING_IDENTIFIER" + Then the response status code is 403 + And the response property "$.status" is 403 + And the response property "$.code" is "SUBSCRIPTION_MISMATCH" + And the response property "$.message" contains a user friendly text + +################## +# Error code 404 +################## + + @connected_network_type_subscriptions_404.1_retrieve_unknown_subscription_id + Scenario: Get subscription when subscriptionId is unknown to the system + Given that there is no valid subscription with "subscriptionId" equal to "id" + When the request "retrieveConnectedNetworkTypeSubscription" is sent + And the path parameter "subscriptionId" is equal to "id" + Then the response status code is 404 + And the response property "$.status" is 404 + And the response property "$.code" is "NOT_FOUND" + And the response property "$.message" contains a user friendly text + + @connected_network_type_subscriptions_404.2_delete_unknown_subscription_id + Scenario: Delete subscription with subscriptionId unknown to the system + Given that there is no valid subscription with "subscriptionId" equal to "id" + When the request "deleteConnectedNetworkTypeSubscription" is sent + And the path parameter "subscriptionId" is equal to "id" + Then the response code is 404 + And the response property "$.status" is 404 + And the response property "$.code" is "NOT_FOUND" And the response property "$.message" contains a user friendly text diff --git a/code/Test_definitions/connected-network-type.feature b/code/Test_definitions/connected-network-type.feature index 50d3d621..10a8d35a 100644 --- a/code/Test_definitions/connected-network-type.feature +++ b/code/Test_definitions/connected-network-type.feature @@ -1,58 +1,73 @@ -@Connected_network_type -Feature: CAMARA Connected Network Type API, vwip - Operations for retrieve network type - -# Input to be provided by the implementation to the tests -# References to OAS spec schemas refer to schemas specifies in connected-network-type.yaml +@Connected_Network_Type +Feature: CAMARA Connected Network Type API, vwip - Operation getConnectedNetworkType + # Input to be provided by the implementation to the tester + # + # Implementation indications: + # * List of device identifier types which are not supported, among: phoneNumber, networkAccessIdentifier, ipv4Address, ipv6Address + # + # Testing assets: + # * A device object where the tester can select between multiple network types. + # * (optional: Additional devices object which supports 2G, 3G, 4G and/or 5G) + # * The known connected Generation of Mobile Communication Technology. + # + # References to OAS spec schemas refer to schemas specifies in connected-network-type.yaml Background: Common Connected Network Type setup Given the resource "{api-root}/connected-network-type/vwip/retrieve" set as base-url 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" is set to a UUID value - -############# Happy Path Scenarios ################## + And the request body is set by default to a request body compliant with the schema "#/components/schemas/ConnectedNetworkTypeRequest" + +########################## +# Happy path scenarios +########################## @connected_network_type_01_generic_success_scenario Scenario: Check the connected network type to which the user device is connected Given a valid testing device supported by the service, identified by the token or provided in the request body And the testing device is connected to a mobile network And the request body is set to a valid request body - When the HTTP "POST" request is sent + When the request "getConnectedNetworkType" is sent Then the response 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/ConnectedNetworkTypeResponse" + And the response body complies with the OAS schema at "#/components/schemas/ConnectedNetworkTypeResponse" And the response property "$.connectedNetworkType" is "2G" or "3G" or "4G" or "5G" + And if the response property "$.lastStatusTime" is present, then the value has a valid date-time format @connected_network_type_02_retrieval_undetermined_network Scenario: The connected network type of the user device can not be determined Given a valid testing device supported by the service, identified by the token or provided in the request body And the testing device is not connected to a mobile network (e.g. connected only to WiFi, or not connected to any network) And the request body is set to a valid request body - When the HTTP "POST" request is sent + When the request "getConnectedNetworkType" is sent Then the response 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/ConnectedNetworkTypeResponse" + And the response body complies with the OAS schema at "#/components/schemas/ConnectedNetworkTypeResponse" And the response property "$.connectedNetworkType" is "UNKNOWN" + And if the response property "$.lastStatusTime" is present, then the value has a valid date-time format -############# Error Response Scenarios ################## - - @connected_network_type_3_device_empty +################# +# Error scenarios for management of input parameter device +################## + + @connected_network_type_C01.01_device_empty Scenario: The device value is an empty object Given the header "Authorization" is set to a valid access token which does not identify a single device And the request body property "$.device" is set to: {} - When the HTTP "POST" request is sent + When the request "getConnectedNetworkType" 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 - @connected_network_type_4_device_identifiers_not_schema_compliant + @connected_network_type_C01.02_device_identifiers_not_schema_compliant Scenario Outline: Some device identifier value does not comply with the schema Given the header "Authorization" is set to a valid access token which does not identify a single device And the request body property "" does not comply with the OAS schema at "" - When the HTTP "POST" request is sent + When the request "getConnectedNetworkType" is sent Then the response status code is 400 And the response property "$.status" is 400 And the response property "$.code" is "INVALID_ARGUMENT" @@ -61,161 +76,138 @@ Feature: CAMARA Connected Network Type API, vwip - Operations for retrieve netwo Examples: | device_identifier | oas_spec_schema | | $.device.phoneNumber | /components/schemas/PhoneNumber | - | $.device.ipv4Address | /components/schemas/NetworkAccessIdentifier | - | $.device.ipv6Address | /components/schemas/DeviceIpv4Addr | - | $.device.networkIdentifier | /components/schemas/DeviceIpv6Address | - - @connected_network_type_5_device_phoneNumber_schema_compliant - # Example of the scenario above with a higher level of specification - # TBD if test plan has to provide specific testing values to provoke an error - Scenario Outline: Device identifier phoneNumber value does not comply with the schema - Given the header "Authorization" is set to a valid access token which does not identify a single device - And the request body property "$.device.phoneNumber" is set to: - 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 + | $.device.ipv4Address | /components/schemas/DeviceIpv4Addr | + | $.device.ipv6Address | /components/schemas/DeviceIpv6Address | + | $.device.networkIdentifier | /components/schemas/NetworkAccessIdentifier | - Examples: - | phone_number_value | - | string_value | - | 1234567890 | - | +12334foo22222 | - | +00012230304913849 | - | 123 | - | ++49565456787 | - - @connected_network_type_6_device_not_found + # This scenario may happen e.g. with 2-legged access tokens, which do not identify a single device. + @connected_network_type_C01.03_device_not_found Scenario: Some identifier cannot be matched to a device - Given the request body property "$.device" is set to a value compliant to the OAS schema at "/components/schemas/Device" but does not identify a device managed by the API provider - And the header "Authorization" is set to a valid access token which does not identify a single device - When the HTTP "POST" request is sent + Given the header "Authorization" is set to a valid access token which does not identify a single device + And the request body property "$.device" is compliant with the schema but does not identify a device whose connectivity is managed by the API provider + When the request "getConnectedNetworkType" 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 - @connected_network_type_7_device_identifiers_unsupported - Scenario: None of the provided device identifiers is supported by the implementation - Given that some type of device identifiers are not supported by the implementation - And the header "Authorization" is set to a valid access token which does not identify a single device - And the request body property "$.device" only includes device identifiers not supported by the implementation - When the HTTP "POST" request is sent + @connected_network_type_C01.04_unnecessary_device + Scenario: Device 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 device + And the request body property "$.device" is set to a valid device, which may or may not be the same device that is identified by the access token + When the request "getConnectedNetworkType" is sent Then the response status code is 422 And the response property "$.status" is 422 - And the response property "$.code" is "UNSUPPORTED_IDENTIFIERS" - And the response property "$.message" contains a user friendly text + And the response property "$.code" is "UNNECESSARY_IDENTIFIER" + And the response property "$.message" contains a user-friendly text - @connected_network_type_8_device_identifiers_mismatch - Scenario: Device identifiers mismatch - # To test this, at least 2 types of identifiers have to be provided, e.g. a phoneNumber and the IP address of a device associated to a different phoneNumber - Given that the implementation supports multiple device identifiers - And the header "Authorization" is set to a valid access token which does not identify a single device - And the request body property "$.device" includes several identifiers, each of them identifying a valid but different device - When the HTTP "POST" request is sent + @connected_network_type_C01.05_missing_device + Scenario: Device not included and cannot be deduced from the access token + Given the header "Authorization" is set to a valid access token which does not identify a single device + And the request body property "$.device" is not included + When the request "getConnectedNetworkType" is sent Then the response status code is 422 And the response property "$.status" is 422 - And the response property "$.code" is "IDENTIFIER_MISMATCH" - And the response property "$.message" contains a user friendly text + And the response property "$.code" is "MISSING_IDENTIFIER" + And the response property "$.message" contains a user-friendly text - @connected_network_type_9_unnecessary_device - Scenario: Device not to be included when it can be deduced from the access token - # This test applies whether the device associated with the access token matches the explicit device identifier or not - # For 3-legged access tokens, an explicit device identifier MUST NOT be provided - Given the header "Authorization" is set to a valid access token identifying a device - And the request body property "$.device" is set to a valid device (which may or may not be the same device) - When the HTTP "POST" request is sent + @connected_network_type_C01.06_unsupported_device + Scenario: None of the provided device identifiers is supported by the implementation + Given that some types of device identifiers are not supported by the implementation + And the header "Authorization" is set to a valid access token which does not identify a single device + And the request body property "$.device" only includes device identifiers not supported by the implementation + When the request "getConnectedNetworkType" 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 + And the response property "$.code" is "UNSUPPORTED_IDENTIFIER" + And the response property "$.message" contains a user-friendly text - @connected_network_type_10_device_not_supported + # When the service is only offered to certain types of devices or subscriptions, e.g. IoT, B2C, etc. + @connected_network_type_C01.07_device_not_supported Scenario: Service not available for the device Given that the service is not available for all devices commercialized by the operator And a valid device, identified by the token or provided in the request body, for which the service is not applicable - When the HTTP "POST" request is sent + When the request "getConnectedNetworkType" 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 + And the response property "$.message" contains a user-friendly text - @connected_network_type_11_device_missing_identifier - Scenario: Cannot be identified from the access token and the optional device object - Given the request body property "$.device" is optional and not set - And the header "Authorization" is set to a valid access token without a device identifier - When the HTTP "POST" request is sent + # Several identifiers provided but they do not identify the same device + # This scenario may happen with 2-legged access tokens, which do not identify a device + @connected_network_type_C01.08_device_identifiers_mismatch + Scenario: Device identifiers mismatch + Given the header "Authorization" is set to a valid access token which does not identify a single device + And at least 2 types of device identifiers are supported by the implementation + And the request body property "$.device" includes several identifiers, each of them identifying a valid but different device + When the request "getConnectedNetworkType" 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 - - # Generic 400 errors - - @connected_network_type_12_no_request_body - Scenario: Missing request body - Given the request body is not included - 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 - - # Other specific 400 errors - - @connected_network_type_13_max_age_schema_compliant - Scenario: Input property values doe not comply with the schema - Given a valid testing device supported by the service, identified by the token or provided in the request body - And the "maxAge" is set to 6a0 - 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 "$.code" is "IDENTIFIER_MISMATCH" And the response property "$.message" contains a user friendly text - # Generic 401 errors +################# +# Error code 401 +################# - @connected_network_type_14_no_authorization_header - Scenario: No Authorization header - Given the header "Authorization" is removed + @connected_network_type_401.1_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 + When the request "getConnectedNetworkType" 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 "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" And the response property "$.message" contains a user friendly text - @connected_network_type_15_expired_access_token - Scenario: Expired access token - Given the header "Authorization" is set to an expired access token + @connected_network_type_401.2_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 + When the request "getConnectedNetworkType" 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 "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" And the response property "$.message" contains a user friendly text - @connected_network_type_16_invalid_access_token - Scenario: Invalid access token - Given the header "Authorization" is set to an invalid access token + @connected_network_type_401.3_malformed_access_token + Scenario: Malformed access token + Given the header "Authorization" is set to a malformed token And the request body is set to a valid request body - When the HTTP "POST" request is sent + When the request "getConnectedNetworkType" is sent Then the response status code is 401 And the response header "Content-Type" is "application/json" And the response property "$.status" is 401 - And the response property "$.code" is "UNAUTHENTICATED" + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" And the response property "$.message" contains a user friendly text - # Generic 403 error +################# +# Error code 403 +################# - @connected_network_type_17_permissions_denied + @connected_network_type_403_permissions_denied Scenario: Client does not have sufficient permissions to perform this action - Given the header "Authorization" is set to an invalid access token + Given header "Authorization" set to an access token not including scope "connected-network-type:read" And the request body is set to a valid request body - When the HTTP "POST" request is sent + When the request "getConnectedNetworkType" is sent Then the response status code is 403 - And the response header "Content-Type" is "application/json" And the response property "$.status" is 403 And the response property "$.code" is "PERMISSION_DENIED" And the response property "$.message" contains a user friendly text + +################# +# Error code 503 +################# + + @connected_network_type_503_network_error + Scenario: Network error temporarily prevents the connected network type from being retrieved + # This test is for use by the API provider only + Given a valid testing device supported by the service, identified by the token or provided in the request body + And the request body is set to a valid request body + And the device is supported by the service, and may be connected or not connected to a mobile network + When the request "getConnectedNetworkType" is sent + And a network error prevents the connected network type from being retrieved + Then the response status code is 503 + And the response property "$.status" is 503 + And the response property "$.code" is "UNAVAILABLE" + And the response property "$.message" contains a user friendly text indicating a temporary network error diff --git a/code/Test_definitions/device-reachability-status-subscriptions.feature b/code/Test_definitions/device-reachability-status-subscriptions.feature index 83dd5f74..f8af2e0a 100644 --- a/code/Test_definitions/device-reachability-status-subscriptions.feature +++ b/code/Test_definitions/device-reachability-status-subscriptions.feature @@ -1,234 +1,622 @@ -@DeviceReachabilityStatusSubscription -Feature: Device Reachability Status Subscriptions API, vwip - Operations Reachability Status Subscription +@Device_Reachability_Status_Subscription +Feature: Device Reachability Status Subscriptions API, vwip - Operations createDeviceReachabilityStatusSubscription, retrieveDeviceReachabilityStatusSubscriptionList, retrieveDeviceReachabilityStatusSubscription and deleteDeviceReachabilityStatusSubscription -# Input to be provided by the implementation to the tests -# References to OAS spec schemas refer to schemas specified in device-reachability-status-subscriptions.yaml + # Input to be provided by the implementation to the tester + # + # Implementation indications: + # * List of device identifier types which are not supported, among: phoneNumber, networkAccessIdentifier, ipv4Address, ipv6Address + # + # Testing assets: + # * A device object which reachability status is known by the network when connected. + # * A device object where you can turn on/off the SMS or data usage reachability. + # * The known reachability status of the testing device + # * A sink-url identified as "callbackUrl", which receives notifications + # + # References to OAS spec schemas refer to schemas specifies in device-reachability-status-subscriptions.yaml Background: Common Device Reachability Status Subscriptions setup Given the resource "{apiroot}/device-reachability-status-subscriptions/vwip" as base-url And the header "Authorization" is set to a valid access token And the header "x-correlator" is set to a UUID value -######### Happy Path Scenarios ################################# +########################## +# Happy path scenarios +########################## - @reachability_status_subscriptions_01_create_reachability_status_subscription_synchronously - Scenario: Create reachability status subscription synchronously - Given that subscriptions are created synchronously - And a valid subscription request body + @reachability_status_subscriptions_01.1_sync_creation_2legs + Scenario Outline: Synchronous subscription creation with 2-legged-access-token + # Some implementations may only support asynchronous subscription creation + Given the header "Authorization" is set to a valid access token which does not identify any device + And the request body is compliant with the OAS schema at "#/component/schemas/SubscriptionRequest" When the request "createDeviceReachabilityStatusSubscription" is sent - Then the response code is 201 + And request property "$.types" is one of the allowed values "" + And request property "$.protocol" is equal to "HTTP" + And a valid phone number identified by "$.config.subscriptionDetail.device.phoneNumber" + And request property "$.sink" is set to a valid callbackUrl + Then the response status code is 201 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/Subscription" + And the response body complies with the OAS schema at "#/components/schemas/Subscription" + And the response properties "$.types", "$.protocol", "$.sink" and "$.config.subscriptionDetail.device.phoneNumber" are present with the values provided in the request + And the response property "$.id" is present + And the response property "$.startsAt", if present, has a valid value with date-time format + And the response property "$.expiresAt", if present, has a valid value with date-time format + And the response property "$.status", if present, has the value "ACTIVATION_REQUESTED", "ACTIVE" or "INACTIVE" - @reachability_status_subscriptions_02_create_reachability_status_subscription_asynchronously - Scenario: Create reachability status subscription asynchronously - Given that subscriptions are created asynchronously - And a valid subscription request body + Examples: + | subscription-creation-types | + | org.camaraproject.device-reachability-status-subscriptions.v0.reachability-data | + | org.camaraproject.device-reachability-status-subscriptions.v0.reachability-sms | + | org.camaraproject.device-reachability-status-subscriptions.v0.reachability-disconnected | + + @reachability_status_subscriptions_01.2_sync_creation_3legs + Scenario Outline: Synchronous subscription creation with 3-legged-access-token + # Some implementations may only support asynchronous subscription creation + Given the header "Authorization" is set to a valid access token which identifies a valid device + And the request body is compliant with the OAS schema at "#/component/schemas/SubscriptionRequest" + When the request "createDeviceReachabilityStatusSubscription" is sent + And request property "$.types" is one of the allowed values "" + And request property "$.protocol" is equal to "HTTP" + And request property "$.sink" is set to a valid callbackUrl + And request property "$.config.subscriptionDetail.device.phoneNumber" is not present + Then the response status code is 201 + 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/Subscription" + And the response properties "$.types", "$.protocol" and "$.sink" are present with the values provided in the request + And the response property "$.id" is present + And the response property "$.startsAt", if present, has a valid value with date-time format + And the response property "$.expiresAt", if present, has a valid value with date-time format + And the response property "$.status", if present, has the value "ACTIVATION_REQUESTED", "ACTIVE" or "INACTIVE" + And the response property "$.config.subscriptionDetail.device" is not present + + Examples: + | subscription-creation-types | + | org.camaraproject.device-reachability-status-subscriptions.v0.reachability-data | + | org.camaraproject.device-reachability-status-subscriptions.v0.reachability-sms | + | org.camaraproject.device-reachability-status-subscriptions.v0.reachability-disconnected | + + @reachability_status_subscriptions_02_async_creation + Scenario Outline: Asynchronous subscription creation with 2- or 3-legged access token + # Some implementations may only support synchronous subscription creation + Given a valid target device, identified by either the access token or in the request body + And the request body is compliant with the OAS schema at "#/component/schemas/SubscriptionRequest" When the request "createDeviceReachabilityStatusSubscription" is sent - Then the response code is 202 + And request property "$.types" is one of the allowed values "" + And request property "$.protocol" is equal to "HTTP" + And request property "$.sink" is set to a valid callbackUrl + Then the response status code is 202 + 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/SubscriptionAsync" + And the response property "$.id" is present + + Examples: + | subscription-creation-types | + | org.camaraproject.device-reachability-status-subscriptions.v0.reachability-data | + | org.camaraproject.device-reachability-status-subscriptions.v0.reachability-sms | + | org.camaraproject.device-reachability-status-subscriptions.v0.reachability-disconnected | + + @reachability_status_subscriptions_03.1_retrieve_by_id_2legs + Scenario: Check existing subscription is retrieved by id with a 2-legged access token + Given a subscription exists and has a subscriptionId equal to "id" + And the header "Authorization" is set to a valid access token which does not identify any device + When the request "retrieveDeviceReachabilityStatusSubscription" is sent + And the path parameter "subscriptionId" is set to "id" + 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/Subscription" + And the response property "$.id" is equal to "id" + And the response property "$.config.subscriptionDetail.device" is present + + @reachability_status_subscriptions_03.2_retrieve_by_id_3legs + Scenario: Check existing subscription is retrieved by id with a 3-legged access token + Given a subscription exists and has a subscriptionId equal to "id" + And the header "Authorization" is set to a valid access token which identifies the device associated with the subscription + When the request "retrieveDeviceReachabilityStatusSubscription" is sent + And the path parameter "subscriptionId" is set to "id" + 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/SubscriptionAsync" - - @reachability_status_subscriptions_03_operation_to_retrieve_list_of_subscriptions_when_no_records - Scenario: Get a list of subscriptions when no subscriptions available - Given a client without subscriptions created + And the response body complies with the OAS schema at "#/components/schemas/Subscription" + And the response property "$.id" is equal to "id" + And the response property "$.config.subscriptionDetail.device" is not present + + @reachability_status_subscriptions_04_retrieve_list_2legs + Scenario: Check existing subscription(s) is/are retrieved in list + Given at least one subscription is existing for the API consumer making this request + And the header "Authorization" is set to a valid access token which does not identify any device When the request "retrieveDeviceReachabilityStatusSubscriptionList" is sent - Then the response code is 200 + 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 is an empty array + And the response body complies with an array of OAS schema defined at "#/components/schemas/Subscription" + And the response body lists all subscriptions belonging to the API consumer - @reachability_status_subscriptions_04_operation_to_retrieve_list_of_subscriptions - Scenario: Get a list of subscriptions - Given a client with subscriptions created + @reachability_status_subscriptions_05_retrieve_list_3legs + Scenario: Check existing subscription(s) is/are retrieved in list + Given the API consumer has at least one active subscription for the device + And the header "Authorization" is set to a valid access token which identifies a valid device associated with one or more subscriptions When the request "retrieveDeviceReachabilityStatusSubscriptionList" is sent - Then the response code is 200 + 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 has an array of items and each item complies with the OAS schema at "/components/schemas/Subscription" + And the response body complies with an array of OAS schema defined at "#/components/schemas/Subscription" + And the response body lists all subscriptions belonging to the API consumer for the identified device + And the response property "$.config.subscriptionDetail.device" is not present in any of the subscription records - @reachability_status_subscriptions_05_operation_to_retrieve_subscription_based_on_an_existing_subscription-id - Scenario: Get a subscription based on existing subscription-id. - Given the path parameter "subscriptionId" is set to the identifier of an existing subscription - When the request "retrieveDeviceReachabilityStatusSubscription" is sent - Then the response code is 200 + @reachability_status_subscriptions_06_retrieve_empty_list_3legs + Scenario: Check no existing subscription is retrieved in list + Given the API consumer has no active subscriptions for the device + And the header "Authorization" is set to a valid access token which identifies a valid device + When the request "retrieveDeviceReachabilityStatusSubscriptionList" 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/Subscription" + And the response body is an empty array - @reachability_status_subscriptions_06_operation_to_delete_subscription_based_on_an_existing_subscription-id - Scenario: Delete a subscription based on existing subscription-id. - Given the path parameter "subscriptionId" is set to the identifier of an existing subscription + @reachability_status_subscriptions_07_delete_subscription_based_on_an_existing_subscription-id + Scenario: Delete the subscription with subscriptionId equal to "id" + Given the API consumer has an active subscription with "subscriptionId" equal to "id" When the request "deleteDeviceReachabilityStatusSubscription" is sent - Then the response code is 202 or 204 + And the path parameter "subscriptionId" is set to "id" + Then the response status code is 202 or 204 And the response header "x-correlator" has same value as the request header "x-correlator" - And if the response property $.status is 204 then response body is not available - And if the response property $.status is 202 then response body complies with the OAS schema at "/components/schemas/SubscriptionAsync" + And if the response property "$.status" is 204 then response body is not present + And if the response property "$.status" is 202 then response body complies with the OAS schema at "#/components/schemas/SubscriptionAsync" and the response property "$.id" is equal to "id" - @reachability_status_subscriptions_07_receive_notification_when_device_reachability_changed_to_data_usage + @reachability_status_subscriptions_08_receive_notification_when_device_reachability_changed_to_data_usage Scenario: Receive notification for reachability-data event - Given that subscriptions are created synchronously - And a valid subscription request body - And the request body property "$.type" is "reachability-data" - When the request "createDeviceReachabilityStatusSubscription" is sent - Then the response code is 201 - And if the device reachability is changed to data usage - Then event notification "reachability-data" is received on callback-url - And sink credentials are received as expected - And notification body complies with the OAS schema at "##/components/schemas/EventReachabilityData" - And type="org.camaraproject.device-reachability-status-subscriptions.v0.reachability-data" - - @reachability_status_subscriptions_08_receive_notification_when_device_reachability_changed_to_sms_usage + Given a valid subscription for that device exists with "subscriptionId" equal to "id" + And the subscription property "$.types" contains the element "org.camaraproject.device-reachability-status-subscriptions.v0.reachability-data" + And the subscription property "$.sink" is a valid callback URL + And the device does not have data connectivity with the API provider's network + When the device's data connectivity status changes (e.g. data connectivity is enabled) + Then event notification "reachability-data" is sent to the specified callback URL + And the sink credentials specified when the subscription was created are included + And notification body complies with the OAS schema at "#/components/schemas/EventReachabilityData" + And the notification property "$.type" is equal to "org.camaraproject.device-reachability-status-subscriptions.v0.reachability-data" + And the notification property "$.data.subscriptionId" is equal to "id" + + @reachability_status_subscriptions_09_receive_notification_when_device_reachability_changed_to_sms_usage Scenario: Receive notification for reachability-sms event - Given that subscriptions are created synchronously - And a valid subscription request body - And the request body property "$.type" is "reachability-sms" - When the request "createDeviceReachabilityStatusSubscription" is sent - Then the response code is 201 - And if the device reachability is changed to sms usage - Then event notification "reachability-sms" is received on callback-url - And sink credentials are received as expected - And notification body complies with the OAS schema at "##/components/schemas/EventReachabilitySms" - And type="org.camaraproject.device-reachability-status-subscriptions.v0.reachability-sms" - - @reachability_status_subscriptions_09_receive_notification_when_device_reachability_changed_to_disconnected + Given a valid subscription for that device exists with "subscriptionId" equal to "id" + And the subscription property "$.types" contains the element "org.camaraproject.device-reachability-status-subscriptions.v0.reachability-sms" + And the subscription property "$.sink" is a valid callback URL + And the device does not have sms connectivity with the API provider's network + When the device's sms connectivity status changes (e.g. sms connectivity is enabled) + Then event notification "reachability-sms" is sent to the specified callback URL + And the sink credentials specified when the subscription was created are included + And notification body complies with the OAS schema at "#/components/schemas/EventReachabilitySms" + And the notification property "$.type" is equal to "org.camaraproject.device-reachability-status-subscriptions.v0.reachability-sms" + And the notification property "$.data.subscriptionId" is equal to "id" + + @reachability_status_subscriptions_10_receive_notification_when_device_reachability_changed_to_disconnected Scenario: Receive notification for reachability-disconnected event - Given that subscriptions are created synchronously - And a valid subscription request body - And the request body property "$.type" is "reachability-disconnected" - When the request "createDeviceReachabilityStatusSubscription" is sent - Then the response code is 201 - And if the device reachability is changed to disconnected - Then event notification "reachability-disconnected" is received on callback-url - And sink credentials are received as expected - And notification body complies with the OAS schema at "##/components/schemas/EventReachabilityDisconnected" - And type="org.camaraproject.device-reachability-status-subscriptions.v0.reachability-disconnected" - - @reachability_status_subscriptions_10_subscription_expiry + Given a valid subscription for that device exists with "subscriptionId" equal to "id" + And the subscription property "$.types" contains the element "org.camaraproject.device-reachability-status-subscriptions.v0.reachability-disconnected" + And the subscription property "$.sink" is a valid callback URL + And the device has data and/or sms connectivity with the API provider's network + When the device loses all connectivity with the API provider's network (e.g. the device is switched off) + Then event notification "reachability-disconnected" is sent to the specified callback URL + And the sink credentials specified when the subscription was created are included + And notification body complies with the OAS schema at "#/components/schemas/EventReachabilityDisconnected" + And the notification property "$.type" is equal to "org.camaraproject.device-reachability-status-subscriptions.v0.reachability-disconnected" + And the notification property "$.data.subscriptionId" is equal to "id" + + @reachability_status_subscriptions_11_subscription_expiry Scenario: Receive notification for subscription-ends event on expiry - Given that subscriptions are created synchronously - And a valid subscription request body - And the request body property "$.subscriptionExpireTime" is set to a value in the near future - When the request "createDeviceReachabilityStatusSubscription" is sent - Then the response code is 201 - Then the subscription is expired - Then event notification "subscription-ends" is received on callback-url - And notification body complies with the OAS schema at "##/components/schemas/EventSubscriptionEnds" - And type="org.camaraproject.device-reachability-status-subscriptions.v0.subscription-ends" - And the response property "$.terminationReason" is "SUBSCRIPTION_EXPIRED" - - @reachability_status_subscriptions_11_subscription_end_when_max_events + Given a valid subscription for a device exists with "subscriptionId" equal to "id" + And the subscription property "$.subscriptionExpireTime" is set to a value in the near future + And the subscription property "$.sink" is a valid callback URL + When the subscriptionExpireTime is reached + Then a subscription termination event notification is sent to the callback URL + And the notification body complies with the OAS schema at "#/components/schemas/EventSubscriptionEnds" + And the notification property "$.type" is "org.camaraproject.device-reachability-status-subscriptions.v0.subscription-ends" + And the notification property "$.data.subscriptionId" is equal to "id" + And the notification property "$.data.terminationReason" is equal to "SUBSCRIPTION_EXPIRED" + + @reachability_status_subscriptions_12_subscription_end_when_max_events Scenario: Receive notification for subscription-ends event on max events reached - Given that subscriptions are created synchronously - And a valid subscription request body - And the request body property "$.type" is "reachability-data" - And the request body property "$.subscriptionMaxEvents" is set to 1 - When the request "createDeviceReachabilityStatusSubscription" is sent - Then the response code is 201 - Then event notification "reachability-data" is received on callback-url - Then event notification "subscription-ends" is received on callback-url - And notification body complies with the OAS schema at "##/components/schemas/EventSubscriptionEnds" - And type="org.camaraproject.device-reachability-status-subscriptions.v0.subscription-ends" - And the response property "$.terminationReason" is "MAX_EVENTS_REACHED" - - @reachability_status_subscriptions_12_subscription_delete_event_validation + Given a valid subscription for a device exists with "subscriptionId" equal to "id" + And the subscription property "$.subscriptionMaxEvents" is set to 1 + And the subscription property "$.sink" is a valid callback URL + When a single notification corresponding to subscription property "$.type" has been sent to the callback URL + Then a subscription termination event notification is sent to the callback URL + And the notification body complies with the OAS schema at "#/components/schemas/EventSubscriptionEnds" + And the notification property "$.type" is equal to "org.camaraproject.device-reachability-status-subscriptions.v0.subscription-ends" + And the notification property "$.data.subscriptionId" is equal to "id" + And the notification request property "$.data.terminationReason" is equal to "MAX_EVENTS_REACHED" + + @reachability_status_subscriptions_13_subscription_delete_event_validation Scenario: Receive notification for subscription-ends event on deletion - Given that subscriptions are created synchronously - And a valid subscription request body + Given a valid subscription for a device exists with "subscriptionId" equal to "id" + And the subscription property "$.sink" is a valid callback URL + When the request "deleteDeviceReachabilityStatusSubscription" is sent + And the path parameter "subscriptionId" is set to "id" + And the response status code is 202 or 204 + Then a subscription termination event notification is sent to the callback URL + And the notification body complies with the OAS schema at "#/components/schemas/EventSubscriptionEnds" + And the notification property "$.type" is equal to "org.camaraproject.device-reachability-status-subscriptions.v0.subscription-ends" + And the notification property "$.data.subscriptionId" is equal to "id" + And the notification request property "$.data.terminationReason" is equal to "SUBSCRIPTION_DELETED" + +################ +# Error scenarios for management of input parameter device +################## + + @reachability_status_subscriptions_C01.01_device_empty + Scenario: The device value is an empty object + Given the header "Authorization" is set to a valid access token which does not identify a single device + And the request body property "$.device" is set to: {} + When the request "createDeviceReachabilityStatusSubscription" 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 + + @reachability_status_subscriptions_C01.02_device_identifiers_not_schema_compliant + Scenario Outline: Some device identifier value does not comply with the schema + Given the header "Authorization" is set to a valid access token which does not identify a single device + And the request body property "" does not comply with the OAS schema at "" + When the request "createDeviceReachabilityStatusSubscription" 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 + + Examples: + | device_identifier | oas_spec_schema | + | $.device.phoneNumber | /components/schemas/PhoneNumber | + | $.device.ipv4Address | /components/schemas/DeviceIpv4Addr | + | $.device.ipv6Address | /components/schemas/DeviceIpv6Address | + | $.device.networkIdentifier | /components/schemas/NetworkAccessIdentifier | + + # This scenario may happen e.g. with 2-legged access tokens, which do not identify a single device. + @reachability_status_subscriptions_C01.03_device_not_found + Scenario: Some identifier cannot be matched to a device + Given the header "Authorization" is set to a valid access token which does not identify a single device + And the request body property "$.device" is compliant with the schema but does not identify a device whose connectivity is managed by the API provider When the request "createDeviceReachabilityStatusSubscription" is sent - Then the response code is 201 - When the request "deleteSubscription" is sent - Then the response code is 202 or 204 - Then event notification "subscription-ends" is received on callback-url - And notification body complies with the OAS schema at "##/components/schemas/EventSubscriptionEnds" - And type="org.camaraproject.device-reachability-status-subscriptions.v0.subscription-ends" - And the response property "$.terminationReason" is "SUBSCRIPTION_DELETED" + 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 + + @reachability_status_subscriptions_C01.04_unnecessary_device + Scenario: Device 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 device + And the request body property "$.device" is also set to a valid device, which may or may not be the same device + When the request "createDeviceReachabilityStatusSubscription" 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 + + @reachability_status_subscriptions_C01.05_missing_device + Scenario: Device not included and cannot be deduced from the access token + Given the header "Authorization" is set to a valid access token which does not identify a single device + And the request body property "$.device" is not included + When the request "createDeviceReachabilityStatusSubscription" 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 + + @reachability_status_subscriptions_C01.06_unsupported_device + Scenario: None of the provided device identifiers is supported by the implementation + Given that some types of device identifiers are not supported by the implementation + And the header "Authorization" is set to a valid access token which does not identify a single device + And the request body property "$.device" only includes device identifiers not supported by the implementation + When the request "createDeviceReachabilityStatusSubscription" is sent + Then the response status code is 422 + And the response property "$.status" is 422 + And the response property "$.code" is "UNSUPPORTED_IDENTIFIER" + And the response property "$.message" contains a user-friendly text -############### Error response scenarios ########################### + # When the service is only offered to certain types of devices or subscriptions, e.g. IoT, B2C, etc. + @reachability_status_subscriptions_C01.07_device_not_supported + Scenario: Service not available for the device + Given that the service is not available for all devices commercialized by the operator + And a valid device, identified by the token or provided in the request body, for which the service is not applicable + When the request "createDeviceReachabilityStatusSubscription" 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 - @reachability_status_subscriptions_13_create_reachability_status_subscription_with_invalid_parameter + # Several identifiers provided but they do not identify the same device + # This scenario may happen with 2-legged access tokens, which do not identify a device + @reachability_status_subscriptions_C01.08_device_identifiers_mismatch + Scenario: Device identifiers mismatch + Given the header "Authorization" is set to a valid access token which does not identify a single device + And at least 2 types of device identifiers are supported by the implementation + And the request body property "$.device" includes several identifiers, each of them identifying a valid but different device + When the request "createDeviceReachabilityStatusSubscription" is sent + Then the response status code is 422 + And the response property "$.status" is 422 + And the response property "$.code" is "IDENTIFIER_MISMATCH" + And the response property "$.message" contains a user friendly text + +################## +# Error code 400 +################## + + @reachability_status_subscriptions_400.1_create_subscription_with_invalid_parameter Scenario: Create subscription with invalid parameter - Given the request body is not compliant with the schema "/components/schemas/SubscriptionRequest" + Given the request body is not compliant with the schema "#/components/schemas/SubscriptionRequest" When the request "createDeviceReachabilityStatusSubscription" is sent - Then the response code is 400 + 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 - @reachability_status_subscriptions_14_creation_of_subscription_with_expiry_time_in_past + @reachability_status_subscriptions_400.2_create_subscription_with_invalid_subscription_expire_time Scenario: Expiry time in past - Given a valid subscription request body - And request body property "$.subscriptionexpiretime" in past + Given the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" + And the request property "$.config.subscriptionExpireTime" is set to a time in the past When the request "createDeviceReachabilityStatusSubscription" is sent - Then the response code is 400 + 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 - @reachability_status_subscription_15_invalid_protocol + @reachability_status_subscriptions_400.3_invalid_eventType + Scenario: Subscription creation with invalid event type + Given the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" + And the request body property "$.types" is set to an invalid value + When the request "createDeviceReachabilityStatusSubscription" 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 + + @reachability_status_subscriptions_400.4_invalid_protocol Scenario: subscription creation with invalid protocol - Given a valid subscription request body - And the request property "$.protocol" is not set to "HTTP" + Given the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" + And the request property "$.protocol" is not equal to "HTTP" When the request "createDeviceReachabilityStatusSubscription" is sent - Then the response property "$.status" is 400 + Then the response status code is 400 + And the response property "$.status" is 400 And the response property "$.code" is "INVALID_PROTOCOL" And the response property "$.message" contains a user friendly text - @reachability_status_subscription_16_invalid_credential_type + @reachability_status_subscriptions_400.5_create_subscription_with_invalid_credential_type Scenario: subscription creation with invalid credential type - Given a valid subscription request body - And the request property "$.credentialType" is not "ACCESSTOKEN" + Given the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" + And the request property "$.sinkCredential.accessTokenType" is equal to "bearer" + And the request property "$.sinkCredential.credentialType" is not equal to "ACCESSTOKEN" When the request "createDeviceReachabilityStatusSubscription" is sent - Then the response property "$.status" is 400 + Then the response status code is 400 + And the response property "$.status" is 400 And the response property "$.code" is "INVALID_CREDENTIAL" And the response property "$.message" contains a user friendly text - - @reachability_status_subscription_17_invalid_access_token_type - Scenario: subscription creation with invalid access token type - Given a valid subscription request body - And the request property "$.accessTokenType" is not "bearer" + + @reachability_status_subscriptions_400.6_create_subscription_with_invalid_access_token_type + Scenario: subscription creation with invalid token + Given the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" + And the request property "$.sinkCredential.credentialType" is equal to "ACCESSTOKEN" + And the request property "$.sinkCredential.accessTokenType" is not equal to "bearer" + When the request "createDeviceReachabilityStatusSubscription" is sent + Then the response status code is 400 + And the response property "$.status" is 400 + And the response property "$.code" is "INVALID_TOKEN" + And the response property "$.message" contains a user friendly text + +################## +# Error code 401 +################## + + @reachability_status_subscriptions_creation_401.1_no_authorization_header + Scenario: No Authorization header + Given the header "Authorization" is removed + And the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" + When the request "createDeviceReachabilityStatusSubscription" is sent + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" + And the response property "$.message" contains a user friendly text + + @reachability_status_subscriptions_creation_401.2_expired_access_token + Scenario: Expired access token + Given the header "Authorization" is set to a previously valid but now expired access token + And the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" + When the request "createDeviceReachabilityStatusSubscription" is sent + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" + And the response property "$.message" contains a user friendly text + + @reachability_status_subscriptions_creation_401.3_malformed_access_token + Scenario: Malformed access token + Given the header "Authorization" is set to a malformed token + And the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" + When the request "createDeviceReachabilityStatusSubscription" is sent + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" + And the response property "$.message" contains a user friendly text + + @reachability_status_subscriptions_retrieve_401.4_no_authorization_header + Scenario: No Authorization header + Given the request header "Authorization" is removed + When the request "retrieveDeviceReachabilityStatusSubscription" is sent + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" + And the response property "$.message" contains a user friendly text + + @reachability_status_subscriptions_retrieve_401.5_expired_access_token + Scenario: Expired access token + Given the header "Authorization" is set to a previously valid but now expired access token + When the request "retrieveDeviceReachabilityStatusSubscription" is sent + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" + And the response property "$.message" contains a user friendly text + + @reachability_status_subscriptions_retrieve_401.6_malformed_access_token + Scenario: Malformed access token + Given the header "Authorization" is set to a malformed token + When the request "retrieveDeviceReachabilityStatusSubscription" is sent + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" + And the response property "$.message" contains a user friendly text + + @reachability_status_subscriptions_delete_401.7_no_authorization_header + Scenario: No Authorization header + Given the request header "Authorization" is removed + When the request "deleteDeviceReachabilityStatusSubscription" is sent + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" + And the response property "$.message" contains a user friendly text + + @reachability_status_subscriptions_delete_401.8_expired_access_token + Scenario: Expired access token + Given the header "Authorization" is set to a previously valid but now expired access token + When the request "deleteDeviceReachabilityStatusSubscription" is sent + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" + And the response property "$.message" contains a user friendly text + + @reachability_status_subscriptions_delete_401.9_malformed_access_token + Scenario: Malformed access token + Given the header "Authorization" is set to a malformed token + When the request "deleteDeviceReachabilityStatusSubscription" is sent + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" + And the response property "$.message" contains a user friendly text + + @reachability_status_subscriptions_retrieve__list_401.10_no_authorization_header + Scenario: No Authorization header + Given the request header "Authorization" is removed + When the request "retrieveDeviceReachabilityStatusSubscriptionList" is sent + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" + And the response property "$.message" contains a user friendly text + + @reachability_status_subscriptions_retrieve_list_401.11_expired_access_token + Scenario: Expired access token + Given the header "Authorization" is set to a previously valid but now expired access token + When the request "retrieveDeviceReachabilityStatusSubscriptionList" is sent + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" + And the response property "$.message" contains a user friendly text + + @reachability_status_subscriptions_retrieve_list_401.12_malformed_access_token + Scenario: Malformed access token + Given the header "Authorization" is set to a malformed token + When the request "retrieveDeviceReachabilityStatusSubscriptionList" is sent + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" + And the response property "$.message" contains a user friendly text + +################## +# Error code 403 +################## + + @reachability_status_subscriptions_create_403.1_permission_denied + Scenario: Subscription creation without having the required scope + # To test this, a token must not have the required scope + Given the header "Authorization" set to an access token not including scope "device-reachability-status-subscriptions:org.camaraproject.device-reachability-status-subscriptions.v0.reachability-data:create" + And the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" + And the request body property "$.types" is equal to "device-reachability-status-subscriptions:org.camaraproject.device-reachability-status-subscriptions.v0.reachability-data" When the request "createDeviceReachabilityStatusSubscription" is sent - Then the response property "$.status" is 400 - And the response property "$.code" is "INVALID_TOKEN" or "INVALID_ARGUMENT" + Then the response status code is 403 + And the response property "$.status" is 403 + And the response property "$.code" is "PERMISSION_DENIED" And the response property "$.message" contains a user friendly text - @reachability_status_subscription_18_invalid_credentials - Scenario: subscription creation with invalid credentials - Given a valid subscription request body - And header "Authorization" token is set to invalid credentials + @reachability_status_subscriptions_create_403.2_permission_denied + Scenario: Subscription creation without having the required scope + # To test this, a token must not have the required scope + Given the header "Authorization" set to an access token not including scope "device-reachability-status-subscriptions:org.camaraproject.device-reachability-status-subscriptions.v0.reachability-sms:create" + And the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" + And the request body property "$.types" is equal to "device-reachability-status-subscriptions:org.camaraproject.device-reachability-status-subscriptions.v0.reachability-sms" When the request "createDeviceReachabilityStatusSubscription" is sent - Then the response property "$.status" is 401 - And the response property "$.code" is "UNAUTHENTICATED" + Then the response status code is 403 + And the response property "$.status" is 403 + And the response property "$.code" is "PERMISSION_DENIED" And the response property "$.message" contains a user friendly text - @reachability_status_subscription_19_permission_denied - Scenario: subscription creation with inconsistent access token for requested events subscription - # To test this, a token does not have the required scope - Given a valid subscription request body - And the request body property "$.device" is set to a valid testing device supported by the service - And header "Authorization" set to access token referring different scope + @reachability_status_subscriptions_create_403.3_permission_denied + Scenario: Subscription creation without having the required scope + # To test this, a token must not have the required scope + Given the header "Authorization" set to an access token not including scope "device-reachability-status-subscriptions:org.camaraproject.device-reachability-status-subscriptions.v0.reachability-disconnected:create" + And the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" + And the request body property "$.types" is equal to "device-reachability-status-subscriptions:org.camaraproject.device-reachability-status-subscriptions.v0.reachability-disconnected" When the request "createDeviceReachabilityStatusSubscription" is sent - Then the response property "$.status" is 403 + Then the response status code is 403 + And the response property "$.status" is 403 And the response property "$.code" is "PERMISSION_DENIED" And the response property "$.message" contains a user friendly text - @reachability_status_subscription_20_inconsistent_access_token_for_requested_events_subscription - Scenario: subscription creation with invalid access token for requested events subscription - # To test this, a token contains an unsupported event type for this API - Given a valid subscription request body - And the request body property "$.device" is set to a valid testing device supported by the service - And the request body property "$.types" contains the supported event type in this API + @reachability_status_subscriptions_create_403.4_subscription_mismatch_for_requested_events_subscription + Scenario: Subscription creation with invalid access token for requested events subscription + Given the header "Authorization" set to an access token that includes only a single subscription scope + And the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" + And the request body property "$.types" is equal to a valid type other than the event corresponding to the access token scope When the request "createDeviceReachabilityStatusSubscription" is sent - Then the response property "$.status" is 403 + Then the response status code is 403 + And the response property "$.status" is 403 And the response property "$.code" is "SUBSCRIPTION_MISMATCH" And the response property "$.message" contains a user friendly text - @reachability_status_subscription_21_unknown_subscription_id - Scenario: Get subscription when subscription-id is unknown to the system - Given the path parameter property "$.subscriptionId" is unknown to the system +################## +# Error code 404 +################## + + @reachability_status_subscriptions_404.1_retrieve_unknown_subscription_id + Scenario: Get subscription when subscriptionId is unknown to the system + Given that there is no valid subscription with "subscriptionId" equal to "id" When the request "retrieveDeviceReachabilityStatusSubscription" is sent - Then the response property "$.status" is 404 + And the path parameter "subscriptionId" is equal to "id" + Then the response status code is 404 + And the response property "$.status" is 404 And the response property "$.code" is "NOT_FOUND" And the response property "$.message" contains a user friendly text + + @reachability_status_subscriptions_404.2_delete_unknown_subscription_id + Scenario: Delete subscription with subscriptionId unknown to the system + Given that there is no valid subscription with "subscriptionId" equal to "id" + When the request "deleteDeviceReachabilityStatusSubscription" is sent + And the path parameter "subscriptionId" is equal to "id" + Then the response code is 404 + And the response property "$.status" is 404 + And the response property "$.code" is "NOT_FOUND" + And the response property "$.message" contains a user friendly text + +################## +# Error code 422 +################## + + @reachability_status_subscriptions_422.1_multi_event_not_supported + Scenario: Multi-event subscriptions are not supported + Given a valid 2- or 3-legged access token + And a request body that is compliant with the OAS schema at "#/component/schemas/SubscriptionRequest" + And request property "$.types" includes more than one subscription-type + When the request "createDeviceReachabilityStatusSubscription" is sent + Then the response status code is 422 + And the response property "$.status" is 422 + And the response property "$.code" is "MULTIEVENT_SUBSCRIPTION_NOT_SUPPORTED" + And the response property "$.message" contains a user friendly text diff --git a/code/Test_definitions/device-reachability-status.feature b/code/Test_definitions/device-reachability-status.feature index 4c1b68ef..fb1620e6 100644 --- a/code/Test_definitions/device-reachability-status.feature +++ b/code/Test_definitions/device-reachability-status.feature @@ -1,144 +1,241 @@ -@Device_reachability_status -Feature: CAMARA Device reachability status API, vwip - Operations for reachability status +@Device_Reachability_Status +Feature: CAMARA Device reachability status API, vwip - Operation getReachabilityStatus + # Input to be provided by the implementation to the tester + # + # Implementation indications: + # * List of device identifier types which are not supported, among: phoneNumber, networkAccessIdentifier, ipv4Address, ipv6Address + # + # Testing assets: + # * A device object which reachability status is known by the network when connected. + # * The known reachability status of the testing device + # + # References to OAS spec schemas refer to schemas specifies in device-reachability-status.yaml -# Input to be provided by the implementation to the tests -# References to OAS spec schemas refer to schemas specifies in device-reachability-status.yaml - - Background: Common Device reachability status setup + Background: Common getReachabilityStatus setup Given the resource "{api-root}/device-reachability-status/vwip/retrieve" set as base-url 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" is set to a UUID value - -############# Happy Path Scenarios ################## + And the request body is set by default to a request body compliant with the schema "#/components/schemas/RequestReachabilityStatus" + +########################## +# Happy path scenarios +########################## - @device_reachability_status_01_reachableAndConnectedSms + @device_reachability_status_01_reachable_and_connected_sms Scenario: Check the reachability status if device is connected with SMS - Given a valid device reachability status request body - And the request body property "$.device" is set to a valid testing device which is connected with sms and supported by the service + Given a valid testing device supported by the service, identified by the token or provided in the request body + And the request body is set to a valid request body + And the device is connected with sms and supported by the service When the request "getReachabilityStatus" is sent Then the response 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/ReachabilityStatusResponse" + And the response body complies with the OAS schema at "#/components/schemas/ReachabilityStatusResponse" And the response property "$.reachable" is true And the response property "$.connectivity" includes "SMS" + And if the response property "$.lastStatusTime" is present, then the value has a valid date-time format - @device_reachability_status_02_reachableAndConnectedData + @device_reachability_status_02_reachable_and_connected_data Scenario: Check the reachability status if device is connected with DATA - Given a valid device reachability status request body - And the request body property "$.device" is set to a valid testing device which is connected with data and supported by the service + Given a valid testing device supported by the service, identified by the token or provided in the request body + And the request body is set to a valid request body + And the device has data connectivity and is supported by the service When the request "getReachabilityStatus" is sent Then the response 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/ReachabilityStatusResponse" + And the response body complies with the OAS schema at "#/components/schemas/ReachabilityStatusResponse" And the response property "$.reachable" is true And the response property "$.connectivity" includes "DATA" + And if the response property "$.lastStatusTime" is present, then the value has a valid date-time format - @device_reachability_status_03_reachableAndConnectedDataAndSms + @device_reachability_status_03_reachable_and_connected_data_and_sms Scenario: Check the reachability status if device is connected with DATA and SMS - Given a valid device reachability status request body - And the request body property "$.device" is set to a valid testing device which is connected with both data and sms, and supported by the service + Given a valid testing device supported by the service, identified by the token or provided in the request body + And the request body is set to a valid request body + And the device has both data and sms connectivity, and is supported by the service When the request "getReachabilityStatus" is sent Then the response 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/ReachabilityStatusResponse" + And the response body complies with the OAS schema at "#/components/schemas/ReachabilityStatusResponse" And the response property "$.reachable" is true And the response property "$.connectivity" includes both "DATA" and "SMS" - - @device_reachability_status_04_notReachable + And if the response property "$.lastStatusTime" is present, then the value has a valid date-time format + + @device_reachability_status_04_not_reachable Scenario: Check the reachability status for an unreachable device - Given a valid device reachability status request body - And the request body property "$.device" is set to a valid testing device which is not connected and supported by the service + Given a valid testing device supported by the service, identified by the token or provided in the request body + And the request body is set to a valid request body + And the device is supported by the service, but is not connected to the API provider's network When the request "getReachabilityStatus" is sent - Then the response 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/ReachabilityStatusResponse" + And the response body complies with the OAS schema at "#/components/schemas/ReachabilityStatusResponse" And the response property "$.reachable" is false - And the response property "$.connectivity" is not returned - -#############Error Response Scenarios################## - - @device_reachability_status_05_deviceStatus_with_invalid_parameter - Scenario: Device reachability status request with invalid parameter - Given the request body is not compliant with the schema "/components/schemas/RequestReachabilityStatus" - When the request "getReachabilityStatus" is sent - Then Response code is 400 + And if the response property "$.lastStatusTime" is present, then the value has a valid date-time format + And the response property "$.connectivity" is not present + +################# +# Error scenarios for management of input parameter device +################## + + @device_reachability_status_C01.01_device_empty + Scenario: The device value is an empty object + Given the header "Authorization" is set to a valid access token which does not identify a single device + And the request body property "$.device" is set to: {} + When the request "getReachabilityStatus" 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 - @device_reachability_status_06_expired_access_token - Scenario: Expired access token - Given a valid device reachability status request body - And header "Authorization" is set to expired token + @device_reachability_status_C01.02_device_identifiers_not_schema_compliant + Scenario Outline: Some device identifier value does not comply with the schema + Given the header "Authorization" is set to a valid access token which does not identify a single device + And the request body property "" does not comply with the OAS schema at "" When the request "getReachabilityStatus" 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 - - @device_reachability_status_07_no_authorization_header - Scenario: No Authorization header - Given a valid device reachability status request body - And header "Authorization" is not available - When the request "getReachabilityStatus" is sent - Then the response status code is 401 - And the response property "$.status" is 401 - And the response property "$.code" is "UNAUTHENTICATED" + 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 - - @device_reachability_status_08_invalid_access_token - Scenario: Invalid access token - Given a valid device reachability status request body - And header "Authorization" set to an invalid access token + + Examples: + | device_identifier | oas_spec_schema | + | $.device.phoneNumber | /components/schemas/PhoneNumber | + | $.device.ipv4Address | /components/schemas/DeviceIpv4Addr | + | $.device.ipv6Address | /components/schemas/DeviceIpv6Address | + | $.device.networkIdentifier | /components/schemas/NetworkAccessIdentifier | + + # This scenario may happen e.g. with 2-legged access tokens, which do not identify a single device. + @device_reachability_status_C01.03_device_not_found + Scenario: Some identifier cannot be matched to a device + Given the header "Authorization" is set to a valid access token which does not identify a single device + And the request body property "$.device" is compliant with the schema, but does not identify a device whose connectivity is managed by the API provider When the request "getReachabilityStatus" is sent - Then the response status code is 401 - And the response header "Content-Type" is "application/json" - And the response property "$.status" is 401 - And the response property "$.code" is "UNAUTHENTICATED" + 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 - - @device_reachability_status_09_deviceStatusWithIdentifiersMismatch - Scenario: Device reachabilityidentifiers mismatch - # To test this, at least 2 types of identifiers have to be provided, e.g. a phoneNumber and the IP address of a Device reachability associated to a different phoneNumber - Given a valid device reachability status request body - And the request body property "$.device" includes several identifiers, each of them identifying a valid but different device + + @device_reachability_status_C01.04_unnecessary_device + Scenario: Device 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 device + And the request body property "$.device" is set to a valid device, which may or may not be the same device that is identified by the access token When the request "getReachabilityStatus" is sent Then the response status code is 422 And the response property "$.status" is 422 - And the response property "$.code" is "DEVICE_IDENTIFIERS_MISMATCH" - And the response property "$.message" contains a user friendly text + And the response property "$.code" is "UNNECESSARY_IDENTIFIER" + And the response property "$.message" contains a user-friendly text - @device_reachability_status_10_deviceStatus_NotApplicable - Scenario: Device reachability not applicable - Given a valid device reachability status request body - And the request body property "$.device" refers to an unknown device + @device_reachability_status_C01.05_missing_device + Scenario: Device not included and cannot be deduced from the access token + Given the header "Authorization" is set to a valid access token which does not identify a single device + And the request body property "$.device" is not included When the request "getReachabilityStatus" is sent Then the response status code is 422 And the response property "$.status" is 422 - And the response property "$.code" is "DEVICE_NOT_APPLICABLE" - And the response property "$.message" contains a user friendly text + And the response property "$.code" is "MISSING_IDENTIFIER" + And the response property "$.message" contains a user-friendly text - @device_reachability_status_11_unable_to_provide_reachability_status - Scenario: Unable to provide reachability status for a device - Given a valid device reachability status request body - And the request body property "$.device" refers to a device having network issue + @device_reachability_status_C01.06_unsupported_device + Scenario: None of the provided device identifiers is supported by the implementation + Given that some types of device identifiers are not supported by the implementation + And the header "Authorization" is set to a valid access token which does not identify a single device + And the request body property "$.device" only includes device identifiers not supported by the implementation When the request "getReachabilityStatus" is sent Then the response status code is 422 And the response property "$.status" is 422 - And the response property "$.code" is "UNABLE_TO_PROVIDE_REACHABILITY_STATUS" - And the response property "$.message" contains a user friendly text + And the response property "$.code" is "UNSUPPORTED_IDENTIFIER" + And the response property "$.message" contains a user-friendly text - @device_reachability_status_12_unsupported_device_identifiers - Scenario: Unsupported device identifiers - Given a valid device reachability status request body - And the request body property "$.device" set to unsupported identifiers value for the service + # When the service is only offered to certain types of devices or subscriptions, e.g. IoT, B2C, etc. + @device_reachability_status_C01.07_device_not_supported + Scenario: Service not available for the device + Given that the service is not available for all devices commercialized by the API provider + And a valid device, identified by the token or provided in the request body, for which the service is not applicable When the request "getReachabilityStatus" is sent Then the response status code is 422 And the response property "$.status" is 422 - And the response property "$.code" is "UNSUPPORTED_DEVICE_IDENTIFIERS" + And the response property "$.code" is "SERVICE_NOT_APPLICABLE" + And the response property "$.message" contains a user-friendly text + + # Several identifiers provided but they do not identify the same device + # This scenario may happen with 2-legged access tokens, which do not identify a device + @device_reachability_status_C01.08_device_identifiers_mismatch + Scenario: Device identifiers mismatch + Given the header "Authorization" is set to a valid access token which does not identify a single device + And at least 2 types of device identifiers are supported by the implementation + And the request body property "$.device" includes several identifiers, each of them identifying a valid but different device + When the request "getReachabilityStatus" is sent + Then the response status code is 422 + And the response property "$.status" is 422 + And the response property "$.code" is "IDENTIFIER_MISMATCH" + And the response property "$.message" contains a user friendly text + +################# +# Error code 401 +################# + + @device_reachability_status_401.1_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 request "getReachabilityStatus" is sent + Then the response status code is 401 + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" + And the response property "$.message" contains a user friendly text + + @device_reachability_status_401.2_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 request "getReachabilityStatus" is sent + Then the response status code is 401 + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" + And the response property "$.message" contains a user friendly text + + @device_reachability_status_401.3_malformed_access_token + Scenario: Malformed access token + Given the header "Authorization" is set to a malformed token + And the request body is set to a valid request body + When the request "getReachabilityStatus" is sent + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" And the response property "$.message" contains a user friendly text + +################# +# Error code 403 +################# + + @device_reachability_status_403_permission_denied + Scenario: OAuth2 token access does not have the required scope + Given header "Authorization" set to an access token not including scope "device-reachability-status:read" + And the request body is set to a valid request body + When the request "getReachabilityStatus" is sent + Then the response status code is 403 + And the response property "$.status" is 403 + And the response property "$.code" is "PERMISSION_DENIED" + And the response property "$.message" contains a user friendly text + +################# +# Error code 503 +################# + + @device_reachability_status_503_network_error + Scenario: Network error temporarily prevents the device reachability status from being retrieved + # This test is for use by the API provider only + Given a valid testing device supported by the service, identified by the token or provided in the request body + And the request body is set to a valid request body + And the device is supported by the service, and may be reachable or not reachable + When the request "getReachabilityStatus" is sent + And a network error prevents the device reachability status from being retrieved + Then the response status code is 503 + And the response property "$.status" is 503 + And the response property "$.code" is "UNAVAILABLE" + And the response property "$.message" contains a user friendly text indicating a temporary network error diff --git a/code/Test_definitions/device-roaming-status-subscriptions.feature b/code/Test_definitions/device-roaming-status-subscriptions.feature index db9a9914..79595184 100644 --- a/code/Test_definitions/device-roaming-status-subscriptions.feature +++ b/code/Test_definitions/device-roaming-status-subscriptions.feature @@ -1,259 +1,646 @@ -@DeviceStatusRoamingSubscription -Feature: Device Roaming Status Subscriptions API, vwip - Operations RoamingStatus +@Device_Status_Roaming_Subscription +Feature: Device Roaming Status Subscriptions API, vwip - Operations createDeviceRoamingStatusSubscription, retrieveDeviceRoamingStatusSubscriptionList, retrieveDeviceRoamingStatusSubscription and deleteDeviceRoamingStatusSubscription -# Input to be provided by the implementation to the tests -# References to OAS spec schemas refer to schemas specified in device-roaming-status-subscriptions.yaml + # Input to be provided by the implementation to the tester + # + # Implementation indications: + # * List of device identifier types which are not supported, among: phoneNumber, networkAccessIdentifier, ipv4Address, ipv6Address + # + # Testing assets: + # * A device object whose roaming status is known by the network when connected. + # * The known roaming status of the testing device + # * A sink-url identified as "callbackUrl", which receives notifications + # + # References to OAS spec schemas refer to schemas specified in device-roaming-status-subscriptions.yaml - Background: Common Device Roaming Status setup + Background: Common Device Roaming Status Subscriptions setup Given the resource "{apiroot}/device-roaming-status-subscriptions/vwip" as base-url And the header "Authorization" is set to a valid access token And the header "x-correlator" is set to a UUID value -######### Happy Path Scenarios ################################# +########################## +# Happy path scenarios +########################## - @roaming_status_subscriptions_01_create_roaming_status_subscription_synchronously - Scenario: Create roaming status subscription synchronously - Given that subscriptions are created synchronously - And a valid subscription request body + @roaming_status_subscriptions_01.1_sync_creation_2legs + Scenario Outline: Synchronous subscription creation with 2-legged-access-token + # Some implementations may only support asynchronous subscription creation + Given the header "Authorization" is set to a valid access token which does not identify any device + And the request body is compliant with the OAS schema at "#/component/schemas/SubscriptionRequest" When the request "createDeviceRoamingStatusSubscription" is sent - Then the response code is 201 + And request property "$.types" is one of the allowed values "" + And request property "$.protocol" is equal to "HTTP" + And a valid phone number identified by "$.config.subscriptionDetail.device.phoneNumber" + And request property "$.sink" is set to a valid callbackUrl + Then the response status code is 201 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/Subscription" + And the response body complies with the OAS schema at "#/components/schemas/Subscription" + And the response properties "$.types", "$.protocol", "$.sink" and "$.config.subscriptionDetail.device.phoneNumber" are present with the values provided in the request + And the response property "$.id" is present + And the response property "$.startsAt", if present, has a valid value with date-time format + And the response property "$.expiresAt", if present, has a valid value with date-time format + And the response property "$.status", if present, has the value "ACTIVATION_REQUESTED", "ACTIVE" or "INACTIVE" - @roaming_status_subscriptions_02_create_roaming_status_subscription_asynchronously - Scenario: Create roaming status subscription asynchronously - Given that subscriptions are created asynchronously - And a valid subscription request body + Examples: + | subscription-creation-types | + | org.camaraproject.device-roaming-status-subscriptions.v0.roaming-status | + | org.camaraproject.device-roaming-status-subscriptions.v0.roaming-on | + | org.camaraproject.device-roaming-status-subscriptions.v0.roaming-off | + | org.camaraproject.device-roaming-status-subscriptions.v0.roaming-change-country | + + @roaming_status_subscriptions_01.2_sync_creation_3legs + Scenario Outline: Synchronous subscription creation with 3-legged-access-token + # Some implementations may only support asynchronous subscription creation + Given the header "Authorization" is set to a valid access token which identifies a valid device + And the request body is compliant with the OAS schema at "#/component/schemas/SubscriptionRequest" When the request "createDeviceRoamingStatusSubscription" is sent - Then the response code is 202 + And request property "$.types" is one of the allowed values "" + And request property "$.protocol" is equal to "HTTP" + And request property "$.sink" is set to a valid callbackUrl + And request property "$.config.subscriptionDetail.device.phoneNumber" is not present + Then the response status code is 201 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/SubscriptionAsync" - - @roaming_status_subscriptions_03_Operation_to_retrieve_list_of_subscriptions_when_no_records - Scenario: Get a list of subscriptions when no subscriptions - Given a client without subscriptions created + And the response body complies with the OAS schema at "#/components/schemas/Subscription" + And the response properties "$.types", "$.protocol" and "$.sink" are present with the values provided in the request + And the response property "$.id" is present + And the response property "$.startsAt", if present, has a valid value with date-time format + And the response property "$.expiresAt", if present, has a valid value with date-time format + And the response property "$.status", if present, has the value "ACTIVATION_REQUESTED", "ACTIVE" or "INACTIVE" + And the response property "$.config.subscriptionDetail.device" is not present + + Examples: + | subscription-creation-types | + | org.camaraproject.device-roaming-status-subscriptions.v0.roaming-status | + | org.camaraproject.device-roaming-status-subscriptions.v0.roaming-on | + | org.camaraproject.device-roaming-status-subscriptions.v0.roaming-off | + | org.camaraproject.device-roaming-status-subscriptions.v0.roaming-change-country | + + @roaming_status_subscriptions_02_async_creation + Scenario Outline: Asynchronous subscription creation with 2- or 3-legged access token + # Some implementations may only support synchronous subscription creation + Given a valid target device, identified by either the access token or in the request body + And the request body is compliant with the OAS schema at "#/component/schemas/SubscriptionRequest" + When the request "createDeviceRoamingStatusSubscription" is sent + And request property "$.types" is one of the allowed values "" + And request property "$.protocol" is equal to "HTTP" + And request property "$.sink" is set to a valid callbackUrl + Then the response status code is 202 + 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/SubscriptionAsync" + And the response property "$.id" is present + + Examples: + | subscription-creation-types | + | org.camaraproject.device-roaming-status-subscriptions.v0.roaming-status | + | org.camaraproject.device-roaming-status-subscriptions.v0.roaming-on | + | org.camaraproject.device-roaming-status-subscriptions.v0.roaming-off | + | org.camaraproject.device-roaming-status-subscriptions.v0.roaming-change-country | + + @roaming_status_subscriptions_03.1_retrieve_by_id_2legs + Scenario: Check existing subscription is retrieved by id with a 2-legged access token + Given a subscription exists and has a subscriptionId equal to "id" + And the header "Authorization" is set to a valid access token which does not identify any device + When the request "retrieveDeviceRoamingStatusSubscription" is sent + And the path parameter "subscriptionId" is set to "id" + 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/Subscription" + And the response property "$.id" is equal to "id" + And the response property "$.config.subscriptionDetail.device" is present + + @roaming_status_subscriptions_03.2_retrieve_by_id_3legs + Scenario: Check existing subscription is retrieved by id with a 3-legged access token + Given a subscription exists and has a subscriptionId equal to "id" + And the header "Authorization" is set to a valid access token which identifies the device associated with the subscription + When the request "retrieveDeviceRoamingStatusSubscription" is sent + And the path parameter "subscriptionId" is set to "id" + 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/Subscription" + And the response property "$.id" is equal to "id" + And the response property "$.config.subscriptionDetail.device" is not present + + @roaming_status_subscriptions_04_retrieve_list_2legs + Scenario: Check existing subscription(s) is/are retrieved in list + Given at least one subscription is existing for the API consumer making this request + And the header "Authorization" is set to a valid access token which does not identify any device When the request "retrieveDeviceRoamingStatusSubscriptionList" is sent - Then the response code is 200 + 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 is an empty array + And the response body complies with an array of OAS schema defined at "#/components/schemas/Subscription" + And the response body lists all subscriptions belonging to the API consumer - @roaming_status_subscriptions_04_Operation_to_retrieve_list_of_subscriptions - Scenario: Get a list of subscriptions. - Given a client with subscriptions created + @roaming_status_subscriptions_05_retrieve_list_3legs + Scenario: Check existing subscription(s) is/are retrieved in list + Given the API consumer has at least one active subscription for the device + And the header "Authorization" is set to a valid access token which identifies a valid device associated with one or more subscriptions When the request "retrieveDeviceRoamingStatusSubscriptionList" is sent - Then the response code is 200 + 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 has an array of items and each item complies with the OAS schema at "/components/schemas/Subscription" + And the response body complies with an array of OAS schema defined at "#/components/schemas/Subscription" + And the response body lists all subscriptions belonging to the API consumer for the identified device + And the response property "$.config.subscriptionDetail.device" is not present in any of the subscription records - @roaming_status_subscriptions_05_Operation_to_retrieve_subscription_based_on_an_existing_subscription-id - Scenario: Get a subscription based on existing subscription-id. - Given the path parameter "subscriptionId" is set to the identifier of an existing subscription - When the request "retrieveDeviceRoamingStatusSubscription" is sent - Then the response code is 200 + @roaming_status_subscriptions_06_retrieve_empty_list_3legs + Scenario: Check no existing subscription is retrieved in list + Given the API consumer has no active subscriptions for the device + And the header "Authorization" is set to a valid access token which identifies a valid device + When the request "retrieveDeviceRoamingStatusSubscriptionList" 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/Subscription" + And the response body is an empty array - @roaming_status_subscriptions_06_Operation_to_delete_subscription_based_on_an_existing_subscription-id - Scenario: Delete a subscription based on existing subscription-id. - Given the path parameter "subscriptionId" is set to the identifier of an existing subscription + @roaming_status_subscriptions_07_delete_subscription_based_on_an_existing_subscription-id + Scenario: Delete the subscription with subscriptionId equal to "id" + Given the API consumer has an active subscription with "subscriptionId" equal to "id" When the request "deleteDeviceRoamingStatusSubscription" is sent - Then the response code is 202 or 204 + And the path parameter "subscriptionId" is set to "id" + Then the response status code is 202 or 204 And the response header "x-correlator" has same value as the request header "x-correlator" - And if the response property $.status is 204 then response body is not available - And if the response property $.status is 202 then response body complies with the OAS schema at "/components/schemas/SubscriptionAsync" + And if the response property "$.status" is 204 then response body is not present + And if the response property "$.status" is 202 then response body complies with the OAS schema at "#/components/schemas/SubscriptionAsync" and the response property "$.id" is equal to "id" - @roaming_status_subscriptions_07_Receive_notification_when_roaming_status_changed_to_on + @roaming_status_subscriptions_08_receive_notification_when_roaming_status_changed_to_on Scenario: Receive notification for roaming-on event - Given that subscriptions are created synchronously - And a valid subscription request body - And the request body property "$.type" is "roaming-on" - When the request "createDeviceRoamingStatusSubscription" is sent - Then the response code is 201 - And if the device switch from roaming "OFF" to roaming "ON" - Then event notification "roaming-on" is received on callback-url - And sink credentials are received as expected - And notification body complies with the OAS schema at "##/components/schemas/EventRoamingOn" - And type="org.camaraproject.roaming-status-subscriptions.v0.roaming-on" - - @roaming_status_subscriptions_08_Receive_notification_when_roaming_status_changed_to_off + Given a valid subscription for that device exists with "subscriptionId" equal to "id" + And the subscription property "$.types" contains the element "org.camaraproject.device-roaming-status-subscriptions.v0.roaming-on" + And the subscription property "$.sink" is a valid callback URL + And the device is not roaming + When the device changes network and is now roaming + Then event notification "roaming-on" is sent to the specified callback URL + And the sink credentials specified when the subscription was created are included + And notification body complies with the OAS schema at "#/components/schemas/EventRoamingOn" + And the notification property "$.type" is equal to "org.camaraproject.device-roaming-status-subscriptions.v0.roaming-on" + And the notification property "$.data.subscriptionId" is equal to "id" + + @roaming_status_subscriptions_09_receive_notification_when_roaming_status_changed_to_off Scenario: Receive notification for roaming-off event - Given that subscriptions are created synchronously - And a valid subscription request body - And the request body property "$.type" is "roaming-off" - When the request "createDeviceRoamingStatusSubscription" is sent - Then the response code is 201 - And if the device switch from roaming "ON" to roaming "OFF" - Then event notification "roaming-off" is received on callback-url - And sink credentials are received as expected - And notification body complies with the OAS schema at "##/components/schemas/EventRoamingOff" - And type="org.camaraproject.roaming-status-subscriptions.v0.roaming-off" - - @roaming_status_subscriptions_09_Receive_notification_when_roaming_status_changed + Given a valid subscription for that device exists with "subscriptionId" equal to "id" + And the subscription property "$.types" contains the element "org.camaraproject.device-roaming-status-subscriptions.v0.roaming-off" + And the subscription property "$.sink" is a valid callback URL + And the device is roaming + When the device changes network and is now not roaming + Then event notification "roaming-off" is sent to the specified callback URL + And the sink credentials specified when the subscription was created are included + And notification body complies with the OAS schema at "#/components/schemas/EventRoamingOff" + And the notification property "$.type" is equal to "org.camaraproject.device-roaming-status-subscriptions.v0.roaming-off" + And the notification property "$.data.subscriptionId" is equal to "id" + + @roaming_status_subscriptions_10_receive_notification_when_roaming_status_changed Scenario: Receive notification for roaming-status changes - Given that subscriptions are created synchronously - And a valid subscription request body - And the request body property "$.type" is "roaming-status" - When the request "createDeviceRoamingStatusSubscription" is sent - Then the response code is 201 - And if the device roaming-status changes - Then event notification "roaming-status" is received on callback-url - And sink credentials are received as expected - And notification body complies with the OAS schema at "##/components/schemas/EventRoamingStatus" - And type="org.camaraproject.roaming-status-subscriptions.v0.roaming-status" - - @roaming_status_subscriptions_10_Receive_notification_when_roaming_change_country + Given a valid subscription for that device exists with "subscriptionId" equal to "id" + And the subscription property "$.types" contains the element "org.camaraproject.device-roaming-status-subscriptions.v0.roaming-status" + And the subscription property "$.sink" is a valid callback URL + When the device changes its roaming status + Then event notification "roaming-status" is sent to the specified callback URL + And the sink credentials specified when the subscription was created are included + And notification body complies with the OAS schema at "#/components/schemas/EventRoamingStatus" + And the notification property "$.type" is equal to "org.camaraproject.device-roaming-status-subscriptions.v0.roaming-status" + And the notification property "$.data.subscriptionId" is equal to "id" + + @roaming_status_subscriptions_11_receive_notification_when_roaming_change_country Scenario: Receive notification for roaming-change-country - Given that subscriptions are created synchronously - And a valid subscription request body - And the request body property "$.type" is "roaming-change-country" - When the request "createDeviceRoamingStatusSubscription" is sent - Then the response code is 201 - And if the device roaming country changes - Then event notification "roaming-change-country" is received on callback-url - And sink credentials are received as expected - And notification body complies with the OAS schema at "##/components/schemas/RoamingChangeCountry" - And type="org.camaraproject.roaming-status-subscriptions.v0.roaming-change-country" - - @roaming_status_subscriptions_11_subscription_expiry + Given a valid subscription for that device exists with "subscriptionId" equal to "id" + And the subscription property "$.types" contains the element "org.camaraproject.device-roaming-status-subscriptions.v0.roaming-change-country" + And the subscription property "$.sink" is a valid callback URL + And the device is roaming + When the device changes to a network in a different country and is still roaming + Then event notification "roaming-change-country" is sent to the specified callback URL + And the sink credentials specified when the subscription was created are included + And notification body complies with the OAS schema at "#/components/schemas/EventRoamingChangeCountry" + And the notification property "$.type" is equal to "org.camaraproject.device-roaming-status-subscriptions.v0.roaming-change-country" + And the notification property "$.data.subscriptionId" is equal to "id" + And the notification property "$.data.countryCode" is present and equal to a valid country code + And the notification property "$.data.countryName" is present and includes a list of all countries corresponding to the country code + + @roaming_status_subscriptions_12_subscription_expiry Scenario: Receive notification for subscription-ends event on expiry - Given that subscriptions are created synchronously - And a valid subscription request body - And the request body property "$.subscriptionExpireTime" is set to a value in the near future - When the request "createDeviceRoamingStatusSubscription" is sent - Then the response code is 201 - And the subscription is expired - And event notification "subscription-ends" is received on callback-url - And notification body complies with the OAS schema at "##/components/schemas/EventSubscriptionEnds" - And type="org.camaraproject.roaming-status-subscriptions.v0.subscription-ends" - And the response property "$.terminationReason" is "SUBSCRIPTION_EXPIRED" - - @roaming_status_subscriptions_12_subscription_ends_when_max_events_reached + Given a valid subscription for a device exists with "subscriptionId" equal to "id" + And the subscription property "$.subscriptionExpireTime" is set to a value in the near future + And the subscription property "$.sink" is a valid callback URL + When the subscriptionExpireTime is reached + Then a subscription termination event notification is sent to the callback URL + And the notification body complies with the OAS schema at "#/components/schemas/EventSubscriptionEnds" + And the notification property "$.type" is "org.camaraproject.device-roaming-status-subscriptions.v0.subscription-ends" + And the notification property "$.data.subscriptionId" is equal to "id" + And the notification property "$.data.terminationReason" is equal to "SUBSCRIPTION_EXPIRED" + + @roaming_status_subscriptions_13_subscription_end_when_max_events Scenario: Receive notification for subscription-ends event on max events reached - Given that subscriptions are created synchronously - And a valid subscription request body - And the request body property "$.type" is "roaming_on" - And the request body property "$.subscriptionMaxEvents" is set to 1 - When the request "createDeviceRoamingStatusSubscription" is sent - Then the response code is 201 - Then event notification "roaming_on" is received on callback-url - Then event notification "subscription-ends" is received on callback-url - And notification body complies with the OAS schema at "##/components/schemas/EventSubscriptionEnds" - And type="org.camaraproject.roaming-status-subscriptions.v0.subscription-ends" - And the response property "$.terminationReason" is "MAX_EVENTS_REACHED" - - @roaming_status_subscriptions_13_subscription_delete_event_validation + Given a valid subscription for a device exists with "subscriptionId" equal to "id" + And the subscription property "$.subscriptionMaxEvents" is set to 1 + And the subscription property "$.sink" is a valid callback URL + When a single notification corresponding to subscription property "$.type" has been sent to the callback URL + Then a subscription termination event notification is sent to the callback URL + And the notification body complies with the OAS schema at "#/components/schemas/EventSubscriptionEnds" + And the notification property "$.type" is equal to "org.camaraproject.device-roaming-status-subscriptions.v0.subscription-ends" + And the notification property "$.data.subscriptionId" is equal to "id" + And the notification request property "$.data.terminationReason" is equal to "MAX_EVENTS_REACHED" + + @roaming_status_subscriptions_14_subscription_delete_event_validation Scenario: Receive notification for subscription-ends event on deletion - Given that subscriptions are created synchronously - And a valid subscription request body + Given a valid subscription for a device exists with "subscriptionId" equal to "id" + And the subscription property "$.sink" is a valid callback URL + When the request "deleteDeviceRoamingStatusSubscription" is sent + And the path parameter "subscriptionId" is set to "id" + And the response status code is 202 or 204 + Then a subscription termination event notification is sent to the callback URL + And the notification body complies with the OAS schema at "#/components/schemas/EventSubscriptionEnds" + And the notification property "$.type" is equal to "org.camaraproject.device-roaming-status-subscriptions.v0.subscription-ends" + And the notification property "$.data.subscriptionId" is equal to "id" + And the notification request property "$.data.terminationReason" is equal to "SUBSCRIPTION_DELETED" + +################ +# Error scenarios for management of input parameter device +################## + + @roaming_status_subscriptions_C01.01_device_empty + Scenario: The device value is an empty object + Given the header "Authorization" is set to a valid access token which does not identify a single device + And the request body property "$.device" is set to: {} When the request "createDeviceRoamingStatusSubscription" is sent - Then the response code is 201 - When the request "deleteSubscription" is sent - Then the response code is 202 or 204 - Then event notification "subscription-ends" is received on callback-url - And notification body complies with the OAS schema at "##/components/schemas/EventSubscriptionEnds" - And type="org.camaraproject.roaming-status-subscriptions.v0.subscription-ends" - And the response property "$.terminationReason" is "SUBSCRIPTION_DELETED" + 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 -############### Error response scenarios ########################### + @roaming_status_subscriptions_C01.02_device_identifiers_not_schema_compliant + Scenario Outline: Some device identifier value does not comply with the schema + Given the header "Authorization" is set to a valid access token which does not identify a single device + And the request body property "" does not comply with the OAS schema at "" + When the request "createDeviceRoamingStatusSubscription" 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 - @roaming_status_subscriptions_14_Create_roaming_status_subscription_with_invalid_parameter + Examples: + | device_identifier | oas_spec_schema | + | $.device.phoneNumber | /components/schemas/PhoneNumber | + | $.device.ipv4Address | /components/schemas/DeviceIpv4Addr | + | $.device.ipv6Address | /components/schemas/DeviceIpv6Address | + | $.device.networkIdentifier | /components/schemas/NetworkAccessIdentifier | + + # This scenario may happen e.g. with 2-legged access tokens, which do not identify a single device. + @roaming_status_subscriptions_C01.03_device_not_found + Scenario: Some identifier cannot be matched to a device + Given the header "Authorization" is set to a valid access token which does not identify a single device + And the request body property "$.device" is compliant with the schema but does not identify a device whose connectivity is managed by the API provider + When the request "createDeviceRoamingStatusSubscription" 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 + + @roaming_status_subscriptions_C01.04_unnecessary_device + Scenario: Device 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 device + And the request body property "$.device" is also set to a valid device, which may or may not be the same device + When the request "createDeviceRoamingStatusSubscription" 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 + + @roaming_status_subscriptions_C01.05_missing_device + Scenario: Device not included and cannot be deduced from the access token + Given the header "Authorization" is set to a valid access token which does not identify a single device + And the request body property "$.device" is not included + When the request "createDeviceRoamingStatusSubscription" 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 + + @roaming_status_subscriptions_C01.06_unsupported_device + Scenario: None of the provided device identifiers is supported by the implementation + Given that some types of device identifiers are not supported by the implementation + And the header "Authorization" is set to a valid access token which does not identify a single device + And the request body property "$.device" only includes device identifiers not supported by the implementation + When the request "createDeviceRoamingStatusSubscription" is sent + Then the response status code is 422 + And the response property "$.status" is 422 + And the response property "$.code" is "UNSUPPORTED_IDENTIFIER" + And the response property "$.message" contains a user-friendly text + + # When the service is only offered to certain types of devices or subscriptions, e.g. IoT, B2C, etc. + @roaming_status_subscriptions_C01.07_device_not_supported + Scenario: Service not available for the device + Given that the service is not available for all devices commercialized by the operator + And a valid device, identified by the token or provided in the request body, for which the service is not applicable + When the request "createDeviceRoamingStatusSubscription" 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 + + # Several identifiers provided but they do not identify the same device + # This scenario may happen with 2-legged access tokens, which do not identify a device + @roaming_status_subscriptions_C01.08_device_identifiers_mismatch + Scenario: Device identifiers mismatch + Given the header "Authorization" is set to a valid access token which does not identify a single device + And at least 2 types of device identifiers are supported by the implementation + And the request body property "$.device" includes several identifiers, each of them identifying a valid but different device + When the request "createDeviceRoamingStatusSubscription" is sent + Then the response status code is 422 + And the response property "$.status" is 422 + And the response property "$.code" is "IDENTIFIER_MISMATCH" + And the response property "$.message" contains a user friendly text + +################## +# Error code 400 +################## + + @roaming_status_subscriptions_400.1_create_subscription_with_invalid_parameter Scenario: Create subscription with invalid parameter - Given the request body is not compliant with the schema "/components/schemas/SubscriptionRequest" + Given the request body is not compliant with the schema "#/components/schemas/SubscriptionRequest" When the request "createDeviceRoamingStatusSubscription" is sent - Then the response code is 400 + 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 - @roaming_status_subscriptions_15_creation_of_subscription_with_expiry_time_in_past + @roaming_status_subscriptions_400.2_create_subscription_with_invalid_subscription_expire_time Scenario: Expiry time in past - Given a valid subscription request body - And request body property "$.subscriptionExpireTime" in past + Given the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" + And the request property "$.config.subscriptionExpireTime" is set to a time in the past + When the request "createDeviceRoamingStatusSubscription" 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 + + @roaming_status_subscriptions_400.3_invalid_eventType + Scenario: Subscription creation with invalid event type + Given the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" + And the request body property "$.types" is set to an invalid value When the request "createDeviceRoamingStatusSubscription" is sent - Then the response code is 400 + 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 - @roaming_status_subscription_16_invalid_protocol + @roaming_status_subscriptions_400.4_invalid_protocol Scenario: subscription creation with invalid protocol - Given a valid subscription request body - And the request property "$.protocol" is not "HTTP" + Given the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" + And the request property "$.protocol" is not equal to "HTTP" When the request "createDeviceRoamingStatusSubscription" is sent - Then the response property "$.status" is 400 + Then the response status code is 400 + And the response property "$.status" is 400 And the response property "$.code" is "INVALID_PROTOCOL" And the response property "$.message" contains a user friendly text - @roaming_status_subscription_17_invalid_credential_type + @roaming_status_subscriptions_400.5_create_subscription_with_invalid_credential_type Scenario: subscription creation with invalid credential type - Given a valid subscription request body - And the request property "$.credentialType" is not "ACCESSTOKEN" + Given the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" + And the request property "$.sinkCredential.accessTokenType" is equal to "bearer" + And the request property "$.sinkCredential.credentialType" is not equal to "ACCESSTOKEN" When the request "createDeviceRoamingStatusSubscription" is sent - Then the response property "$.status" is 400 + Then the response status code is 400 + And the response property "$.status" is 400 And the response property "$.code" is "INVALID_CREDENTIAL" And the response property "$.message" contains a user friendly text - - @roaming_status_subscription_18_invalid_access_token_type - Scenario: subscription creation with invalid access token type - Given a valid subscription request body - And the request property "$.accessTokenType" is not "bearer" + + @roaming_status_subscriptions_400.6_create_subscription_with_invalid_access_token_type + Scenario: subscription creation with invalid token + Given the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" + And the request property "$.sinkCredential.credentialType" is equal to "ACCESSTOKEN" + And the request property "$.sinkCredential.accessTokenType" is not equal to "bearer" When the request "createDeviceRoamingStatusSubscription" is sent - Then the response property "$.status" is 400 - And the response property "$.code" is "INVALID_TOKEN" or "INVALID_ARGUMENT" + Then the response status code is 400 + And the response property "$.status" is 400 + And the response property "$.code" is "INVALID_TOKEN" And the response property "$.message" contains a user friendly text - @roaming_status_subscription_19_invalid_credentials - Scenario: subscription creation with invalid credentials - Given a valid subscription request body - And header "Authorization" token is set to invalid credentials +################## +# Error code 401 +################## + + @roaming_status_subscriptions_creation_401.1_no_authorization_header + Scenario: No Authorization header + Given the header "Authorization" is removed + And the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" + Then the response status code is 401 + And the response header "Content-Type" is "application/json" When the request "createDeviceRoamingStatusSubscription" is sent Then the response property "$.status" is 401 - And the response property "$.code" is "UNAUTHENTICATED" + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" And the response property "$.message" contains a user friendly text - @roaming_status_subscription_20_permission_denied - Scenario: subscription creation with inconsistent access token for requested events subscription - # To test this, a token does not have the required scope - Given a valid subscription request body - And the request body property "$.device" is set to a valid testing device supported by the service - And header "Authorization" set to access token referring different scope + @roaming_status_subscriptions_creation_401.2_expired_access_token + Scenario: Expired access token + Given the header "Authorization" is set to a previously valid but now expired access token + And the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" When the request "createDeviceRoamingStatusSubscription" is sent - Then the response property "$.status" is 403 + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" + And the response property "$.message" contains a user friendly text + + @roaming_status_subscriptions_creation_401.3_malformed_access_token + Scenario: Malformed access token + Given the header "Authorization" is set to a malformed token + And the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" + When the request "createDeviceRoamingStatusSubscription" is sent + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" + And the response property "$.message" contains a user friendly text + + @roaming_status_subscriptions_retrieve_401.4_no_authorization_header + Scenario: No Authorization header + Given the request header "Authorization" is removed + When the request "retrieveDeviceRoamingStatusSubscription" is sent + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" + And the response property "$.message" contains a user friendly text + + @roaming_status_subscriptions_retrieve_401.5_expired_access_token + Scenario: Expired access token + Given the header "Authorization" is set to a previously valid but now expired access token + When the request "retrieveDeviceRoamingStatusSubscription" is sent + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" + And the response property "$.message" contains a user friendly text + + @roaming_status_subscriptions_retrieve_401.6_malformed_access_token + Scenario: Malformed access token + Given the header "Authorization" is set to a malformed token + When the request "retrieveDeviceRoamingStatusSubscription" is sent + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" + And the response property "$.message" contains a user friendly text + + @roaming_status_subscriptions_delete_401.7_no_authorization_header + Scenario: No Authorization header + Given the request header "Authorization" is removed + When the request "deleteDeviceRoamingStatusSubscription" is sent + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" + And the response property "$.message" contains a user friendly text + + @roaming_status_subscriptions_delete_401.8_expired_access_token + Scenario: Expired access token + Given the header "Authorization" is set to a previously valid but now expired access token + When the request "deleteDeviceRoamingStatusSubscription" is sent + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" + And the response property "$.message" contains a user friendly text + + @roaming_status_subscriptions_delete_401.9_malformed_access_token + Scenario: Malformed access token + Given the header "Authorization" is set to a malformed token + When the request "deleteDeviceRoamingStatusSubscription" is sent + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" + And the response property "$.message" contains a user friendly text + + @roaming_status_subscriptions_retrieve__list_401.10_no_authorization_header + Scenario: No Authorization header + Given the request header "Authorization" is removed + When the request "deleteDeviceRoamingStatusSubscriptionList" is sent + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" + And the response property "$.message" contains a user friendly text + + @roaming_status_subscriptions_retrieve_list_401.11_expired_access_token + Scenario: Expired access token + Given the header "Authorization" is set to a previously valid but now expired access token + When the request "deleteDeviceRoamingStatusSubscriptionList" is sent + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" + And the response property "$.message" contains a user friendly text + + @roaming_status_subscriptions_retrieve_list_401.12_malformed_access_token + Scenario: Malformed access token + Given the header "Authorization" is set to a malformed token + When the request "deleteDeviceRoamingStatusSubscriptionList" is sent + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" + And the response property "$.message" contains a user friendly text + +################## +# Error code 403 +################## + + @roaming_status_subscriptions_create_403.1_permission_denied + Scenario: subscription creation without having the required scope + Given the header "Authorization" set to an access token not including scope "device-roaming-status-subscriptions:org.camaraproject.device-roaming-status-subscriptions.v0.roaming-on:create" + And the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" + And the request body property "$.types" is equal to "device-roaming-status-subscriptions:org.camaraproject.device-roaming-status-subscriptions.v0.roaming-on" + When the request "createDeviceRoamingStatusSubscription" is sent + Then the response status code is 403 + And the response property "$.status" is 403 And the response property "$.code" is "PERMISSION_DENIED" And the response property "$.message" contains a user friendly text - @roaming_status_subscription_21_unnecessary_identifier - Scenario: subscription creation with both a 3-legged token and explicit device identifier - # This test applies whether the device associated with the access token matches the explicit device identifier or not - # For 3-legged access tokens, an explicit device identifier MUST NOT be provided - Given a valid subscription request body - And the request body property "$.device" is set to a valid testing device supported by the service - And header "Authorization" set to access token also referring to a device (which may or may not be the same device) + @roaming_status_subscriptions_create_403.2_permission_denied + Scenario: subscription creation without having the required scope + Given the header "Authorization" set to an access token not including scope "device-roaming-status-subscriptions:org.camaraproject.device-roaming-status-subscriptions.v0.roaming-off:create" + And the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" + And the request body property "$.types" is equal to "device-roaming-status-subscriptions:org.camaraproject.device-roaming-status-subscriptions.v0.roaming-off" When the request "createDeviceRoamingStatusSubscription" is sent - Then the response property "$.status" is 422 - And the response property "$.code" is "UNNECESSARY_IDENTIFIER" + Then the response status code is 403 + And the response property "$.status" is 403 + And the response property "$.code" is "PERMISSION_DENIED" + And the response property "$.message" contains a user friendly text + + @roaming_status_subscriptions_create_403.1_permission_denied + Scenario: subscription creation without having the required scope + Given the header "Authorization" set to an access token not including scope "device-roaming-status-subscriptions:org.camaraproject.device-roaming-status-subscriptions.v0.roaming-status:create" + And the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" + And the request body property "$.types" is equal to "device-roaming-status-subscriptions:org.camaraproject.device-roaming-status-subscriptions.v0.roaming-status" + When the request "createDeviceRoamingStatusSubscription" is sent + Then the response status code is 403 + And the response property "$.status" is 403 + And the response property "$.code" is "PERMISSION_DENIED" + And the response property "$.message" contains a user friendly text + + @roaming_status_subscriptions_create_403.1_permission_denied + Scenario: subscription creation without having the required scope + Given the header "Authorization" set to an access token not including scope "device-roaming-status-subscriptions:org.camaraproject.device-roaming-status-subscriptions.v0.roaming-change-country:create" + And the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" + And the request body property "$.types" is equal to "device-roaming-status-subscriptions:org.camaraproject.device-roaming-status-subscriptions.v0.roaming-change-country" + When the request "createDeviceRoamingStatusSubscription" is sent + Then the response status code is 403 + And the response property "$.status" is 403 + And the response property "$.code" is "PERMISSION_DENIED" And the response property "$.message" contains a user friendly text - @roaming_status_subscription_22_inconsistent_access_token_for_requested_events_subscription - Scenario: subscription creation with invalid access token for requested events subscription - # To test this, a token contains an unsupported event type for this API - Given a valid subscription request body - And the request body property "$.device" is set to a valid testing device supported by the service - And the request body property "$.types" contains the supported event type in this API + @roaming_status_subscriptions_create_403.5_subscription_mismatch_for_requested_events_subscription + Scenario: Subscription creation with invalid access token for requested events subscription + Given the header "Authorization" set to an access token that includes only a single subscription scope + And the request body is compliant with the schema "#/components/schemas/SubscriptionRequest" + And the request body property "$.types" is equal to a valid type other than the event corresponding to the access token scope When the request "createDeviceRoamingStatusSubscription" is sent - Then the response property "$.status" is 403 + Then the response status code is 403 + And the response property "$.status" is 403 And the response property "$.code" is "SUBSCRIPTION_MISMATCH" And the response property "$.message" contains a user friendly text - @roaming_status_subscription_23_unknown_subscription_id - Scenario: Get subscription when subscription-id is unknown to the system - Given the path parameter property "$.subscriptionId" is unknown to the system +################## +# Error code 404 +################## + + @roaming_status_subscriptions_404.1_retrieve_unknown_subscription_id + Scenario: Get subscription when subscriptionId is unknown to the system + Given that there is no valid subscription with "subscriptionId" equal to "id" When the request "retrieveDeviceRoamingStatusSubscription" is sent - Then the response property "$.status" is 404 + And the path parameter "subscriptionId" is equal to "id" + Then the response status code is 404 + And the response property "$.status" is 404 And the response property "$.code" is "NOT_FOUND" And the response property "$.message" contains a user friendly text + + @roaming_status_subscriptions_404.2_delete_unknown_subscription_id + Scenario: Delete subscription with subscriptionId unknown to the system + Given that there is no valid subscription with "subscriptionId" equal to "id" + When the request "deleteDeviceRoamingStatusSubscription" is sent + And the path parameter "subscriptionId" is equal to "id" + Then the response code is 404 + And the response property "$.status" is 404 + And the response property "$.code" is "NOT_FOUND" + And the response property "$.message" contains a user friendly text + +################## +# Error code 422 +################## + + @roaming_status_subscriptions_C01.08_multi_event_not_supported + Scenario: Multi-event subscriptions are not supported + Given a valid 2- or 3-legged access token + And a request body that is compliant with the OAS schema at "#/component/schemas/SubscriptionRequest" + And request property "$.types" includes more than one subscription-type + When the request "createDeviceRoamingStatusSubscription" is sent + Then the response status code is 422 + And the response property "$.status" is 422 + And the response property "$.code" is "MULTIEVENT_SUBSCRIPTION_NOT_SUPPORTED" + And the response property "$.message" contains a user friendly text diff --git a/code/Test_definitions/device-roaming-status.feature b/code/Test_definitions/device-roaming-status.feature index da8f89ee..5b9ebb92 100644 --- a/code/Test_definitions/device-roaming-status.feature +++ b/code/Test_definitions/device-roaming-status.feature @@ -1,136 +1,216 @@ @Device_Roaming_Status -Feature: CAMARA Device Roaming Status API, vwip - Operations for Roaming Status +Feature: CAMARA Device Roaming Status API, vwip - Operation getRoamingStatus + # Input to be provided by the implementation to the tester + # + # Implementation indications: + # * List of device identifier types which are not supported, among: phoneNumber, networkAccessIdentifier, ipv4Address, ipv6Address + # + # Testing assets: + # * A device object which roaming status is known by the network when connected. + # * The known roaming status of the testing device + # + # References to OAS spec schemas refer to schemas specifies in device-roaming-status.yaml -# Input to be provided by the implementation to the tests -# References to OAS spec schemas refer to schemas specifies in device-roaming-status.yaml - - Background: Common Device Roaming status setup + Background: Common getRoamingStatus setup Given the resource "{api-root}/device-roaming-status/vwip/retrieve" set as base-url 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" is set to a UUID value - -#############Happy Path Scenarios################## + And the request body is set by default to a request body compliant with the schema "#/components/schemas/RoamingStatusRequest" + +########################## +# Happy path scenarios +########################## - @device_roaming_status_01_roaming_status_true + @device_roaming_status_01_roaming_status_true_with_country_code Scenario: Check the roaming status when device is in the roaming mode - Given a valid devicestatus request body - And the request body property "$.device" is set to a valid testing device which is in roaming and supported by the service + Given a valid testing device supported by the service, identified by the token or provided in the request body + And the request body is set to a valid request body + And the device which is in roaming inside Germany and supported by the service When the request "getRoamingStatus" is sent Then the response 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/RoamingStatusResponse" - And the response property "$.status" is 200 - And the response property "$.code" is "OK" - And the response property "$.message" contains a user friendly text - Then the roaming status is true + And the response body complies with the OAS schema at "#/components/schemas/RoamingStatusResponse" + And the response property "$.roaming" is "true" + And the response property "$.countryCode" has the value "262" as the Mobile Country Code (MCC) for Germany + And the response property "$.countryName" is a non-empty array containing the ISO 3166 ALPHA-2 country-code ["DE"] + And if the response property "$.lastStatusTime" is present, then the value has a valid date-time format @device_roaming_status_02_roaming_status_false Scenario: Check the roaming state synchronously if the device is not in the roaming mode - Given a valid devicestatus request body - And the request body property "$.device" is set to a valid testing device which is not in roaming and supported by the service + Given a valid testing device supported by the service, identified by the token or provided in the request body + And the request body is set to a valid request body + And the device which is not in roaming and supported by the service When the request "getRoamingStatus" is sent Then the response 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/RoamingStatusResponse" - And the response property "$.status" is 200 - And the response property "$.code" is "OK" - Then the roaming status is false - -#############Error Response Scenarios################## - - @device_roaming_status_03_deviceStatus_with_invalid_parameter - Scenario: Device status request with invalid parameter - Given the request body is not compliant with the schema "/components/schemas/RequestRoamingStatus" + And the response body complies with the OAS schema at "#/components/schemas/RoamingStatusResponse" + And the response property "$.roaming" is "false" + And the response property "$.countryCode" is not present + And the response property "$.countryName" is not present + And if the response property "$.lastStatusTime" is present, then the value is a valid date-time format + +################# +# Error scenarios for management of input parameter device +################## + + @device_roaming_status_C01.01_device_empty + Scenario: The device value is an empty object + Given the header "Authorization" is set to a valid access token which does not identify a single device + And the request body property "$.device" is set to: {} When the request "getRoamingStatus" is sent - Then Response code is 400 + 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 - @device_roaming_status_04_no_authorization_header - Scenario: No Authorization header - Given the header "Authorization" is removed + @device_roaming_status_C01.02_device_identifiers_not_schema_compliant + Scenario Outline: Some device identifier value does not comply with the schema + Given the header "Authorization" is set to a valid access token which does not identify a single device + And the request body property "" does not comply with the OAS schema at "" + When the request "getRoamingStatus" 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 + + Examples: + | device_identifier | oas_spec_schema | + | $.device.phoneNumber | /components/schemas/PhoneNumber | + | $.device.ipv4Address | /components/schemas/DeviceIpv4Addr | + | $.device.ipv6Address | /components/schemas/DeviceIpv6Address | + | $.device.networkIdentifier | /components/schemas/NetworkAccessIdentifier | + + # This scenario may happen e.g. with 2-legged access tokens, which do not identify a single device. + @device_roaming_status_C01.03_device_not_found + Scenario: Some identifier cannot be matched to a device + Given the header "Authorization" is set to a valid access token which does not identify a single device + And the request body property "$.device" is compliant with the schema, but does not identify a device whose connectivity is managed by the API provider + When the request "getRoamingStatus" 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 + + @device_roaming_status_C01.04_unnecessary_device + Scenario: Device 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 device + And the request body property "$.device" is set to a valid device, which may or may not be the same device that is identified by the access token + When the request "getRoamingStatus" 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 + + @device_roaming_status_C01.05_missing_device + Scenario: Device not included and cannot be deduced from the access token + Given the header "Authorization" is set to a valid access token which does not identify a single device + And the request body property "$.device" is not included + When the request "getRoamingStatus" 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 + + @device_roaming_status_C01.06_unsupported_device + Scenario: None of the provided device identifiers is supported by the implementation + Given that some types of device identifiers are not supported by the implementation + And the header "Authorization" is set to a valid access token which does not identify a single device + And the request body property "$.device" only includes device identifiers not supported by the implementation + When the request "getRoamingStatus" is sent + Then the response status code is 422 + And the response property "$.status" is 422 + And the response property "$.code" is "UNSUPPORTED_IDENTIFIER" + And the response property "$.message" contains a user-friendly text + + # When the service is only offered to certain types of devices or subscriptions, e.g. IoT, B2C, etc. + @device_roaming_status_C01.07_device_not_supported + Scenario: Service not available for the device + Given that the service is not available for all devices commercialized by the operator + And a valid device, identified by the token or provided in the request body, for which the service is not applicable + When the request "getRoamingStatus" 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 + + # Several identifiers provided but they do not identify the same device + # This scenario may happen with 2-legged access tokens, which do not identify a device + @device_roaming_status_C01.08_device_identifiers_mismatch + Scenario: Device identifiers mismatch + Given the header "Authorization" is set to a valid access token which does not identify a single device + And at least 2 types of device identifiers are supported by the implementation + And the request body property "$.device" includes several identifiers, each of them identifying a valid but different device + When the request "getRoamingStatus" is sent + Then the response status code is 422 + And the response property "$.status" is 422 + And the response property "$.code" is "IDENTIFIER_MISMATCH" + And the response property "$.message" contains a user friendly text + +################# +# Error code 401 +################# + + @device_roaming_status_401.1_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 "getRoamingStatus" request is sent + When the request "getRoamingStatus" 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 "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" And the response property "$.message" contains a user friendly text - @device_roaming_status_05_expired_access_token - Scenario: Expired access token - Given the header "Authorization" is set to an expired access token + @device_roaming_status_401.2_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 "getRoamingStatus" request is sent + When the request "getRoamingStatus" 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 "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" And the response property "$.message" contains a user friendly text - @device_roaming_status_06_invalid_access_token - Scenario: Invalid access token - Given the header "Authorization" is set to an invalid access token + @device_roaming_status_401.3_malformed_access_token + Scenario: Malformed access token + Given the header "Authorization" is set to a malformed token And the request body is set to a valid request body - When the HTTP "getRoamingStatus" request is sent + When the request "getRoamingStatus" is sent Then the response status code is 401 And the response header "Content-Type" is "application/json" And the response property "$.status" is 401 - And the response property "$.code" is "UNAUTHENTICATED" + And the response property "$.code" is "UNAUTHENTICATED" or "AUTHENTICATION_REQUIRED" And the response property "$.message" contains a user friendly text - - @device_roaming_status_07_permissions_denied - Scenario: Client does not have sufficient permissions to perform this action - # To test this, a token has to be obtained for a different device - Given the header "Authorization" is set to an invalid access token + +################# +# Error code 403 +################# + + @device_roaming_status_403_permission_denied + Scenario: OAuth2 token access does not have the required scope + Given header "Authorization" set to an access token not including scope "device-roaming-status:read" And the request body is set to a valid request body When the request "getRoamingStatus" is sent Then the response status code is 403 And the response property "$.status" is 403 And the response property "$.code" is "PERMISSION_DENIED" And the response property "$.message" contains a user friendly text - - @device_roaming_status_08_deviceStatusWithIdentifiersMismatch - Scenario: Device identifiers mismatch - # To test this, at least 2 types of identifiers have to be provided, e.g. a phoneNumber and the IP address of a device associated to a different phoneNumber - Given a valid devicestatus request body - And the request body property "$.device" includes several identifiers, each of them identifying a valid but different device - When the request "getRoamingStatus" is sent - Then the response status code is 422 - And the response property "$.status" is 422 - And the response property "$.code" is "DEVICE_IDENTIFIERS_MISMATCH" - And the response property "$.message" contains a user friendly text - @device_roaming_status_09_device_not_supported - Scenario: Service not available for the device - Given that the service is not available for all devices commercialized by the operator - And a valid device, identified by the token or provided in the request body, for which the service is not applicable - When the request "getRoamingStatus" 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 +################# +# Error code 503 +################# - @device_roaming_status_10_unnecessary_device - Scenario: Device not to be included when it can be deduced from the access token - # This test applies whether the device associated with the access token matches the explicit device identifier or not - # For 3-legged access tokens, an explicit device identifier MUST NOT be provided - Given the header "Authorization" is set to a valid access token identifying a device - And the request body property "$.device" is set to a valid device (which may or may not be the same device) - When the request "getRoamingStatus" 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 - - @device_roaming_status_11_unable_to_provide_roaming_status - Scenario: Unable to provide roaming status for a device - Given a valid devicestatus request body - And the request body property "$.device" refers to a device having network issue + @device_roaming_status_503_network_error + Scenario: Network error temporarily prevents the device roaming status from being retrieved + # This test is for use by the API provider only + Given a valid testing device supported by the service, identified by the token or provided in the request body + And the request body is set to a valid request body + And the device is supported by the service, and may be roaming or not roaming When the request "getRoamingStatus" is sent + And a network error prevents the device roaming status from being retrieved Then the response status code is 503 And the response property "$.status" is 503 And the response property "$.code" is "UNAVAILABLE" - And the response property "$.message" contains a user friendly text + And the response property "$.message" contains a user friendly text indicating a temporary network error