diff --git a/code/API_definitions/qos-booking-and-assignment.yaml b/code/API_definitions/qos-booking-and-assignment.yaml index adc9bca..9472054 100644 --- a/code/API_definitions/qos-booking-and-assignment.yaml +++ b/code/API_definitions/qos-booking-and-assignment.yaml @@ -184,22 +184,28 @@ info: | Code | When raised | Operations | |---|---|---| | `INVALID_ARGUMENT` | Malformed request body, unrecognised field, or invalid field value. | All write operations | - | `OUT_OF_RANGE` | A numeric value (e.g. device count) exceeds its declared bounds. | `createBooking`, `assignDevices` | + | `OUT_OF_RANGE` | A numeric value (e.g. device count) exceeds its declared bounds. | `createBooking`, `assignDevices`, `releaseDevices` | | `QOS_BOOKING_AND_ASSIGNMENT.DURATION_OUT_OF_RANGE` | The requested booking duration exceeds the maximum allowed by the selected QoS profile. | `createBooking` only | - | `INVALID_SINK` | The `sink` URL is not a valid callback endpoint or uses an unsupported protocol. | `createBooking` only | + | `INVALID_CREDENTIAL` | The `sinkCredential.credentialType` is not supported (only `ACCESSTOKEN` and `PRIVATE_KEY_JWT` are). | `createBooking`, `assignDevices`, `releaseDevices` | + | `INVALID_TOKEN` | The `sinkCredential.accessTokenType` is not supported (only `bearer` is). | `createBooking`, `assignDevices`, `releaseDevices` | + | `INVALID_SINK` | The `sink` URL is not a valid callback endpoint or uses an unsupported protocol. | `createBooking`, `assignDevices`, `releaseDevices` | ## API-specific 409 codes | Code | When raised | Operations | |---|---|---| - | `INCOMPATIBLE_STATE` | The operation is not valid for the booking's current `bookingStatus`. Examples: assigning devices to a `TERMINATED` booking; `deleteBooking` when devices remain assigned (provider-dependent — see `deleteBooking` description). | `createBooking`, `deleteBooking`, `assignDevices`, `releaseDevices` | + | `ALREADY_EXISTS` | A booking with identical parameters already exists for this consumer. | `createBooking` only | + | `INCOMPATIBLE_STATE` | The operation is not valid for the booking's current `bookingStatus`. Examples: assigning devices to a `TERMINATED` booking; `deleteBooking` when devices remain assigned (provider-dependent — see `deleteBooking` description). | `deleteBooking`, `assignDevices`, `releaseDevices` | | `ABORTED` | A concurrent operation of the same type is already in progress for the same booking. Retry after the in-progress operation resolves. | `assignDevices`, `releaseDevices` | - | `ALREADY_EXISTS` | A booking with identical parameters already exists for this consumer. | `createBooking` | - | `CONFLICT` | A duplicate resource entry was detected. | `createBooking` | - > **Note:** `ALREADY_EXISTS` and `CONFLICT` do not apply to read operations or - > `deleteBooking` / `releaseDevices`. These codes are included in the shared `Generic409` - > definition and will be scoped to individual operations in a future cleanup. + ## API-specific 422 codes + + | Code | When raised | Operations | + |---|---|---| + | `EVENT_NOTIFICATIONS_NOT_SUPPORTED` | A `sink` is provided but the API provider does not support event notification delivery. The request is rejected and no booking or assignment is created; retry without `sink`. | `createBooking`, `assignDevices`, `releaseDevices` | + | `QOS_BOOKING_AND_ASSIGNMENT.DEVICE_QUOTA_EXCEEDED` | The number of devices in the request exceeds the remaining device capacity of the booking (`remainingDevices`). | `assignDevices` only | + + The device identification codes (`MISSING_IDENTIFIER`, `UNNECESSARY_IDENTIFIER`, `UNSUPPORTED_IDENTIFIER`, `SERVICE_NOT_APPLICABLE`) apply to `assignDevices`, `releaseDevices` and `retrieveBookingByDevice`, as described in the section "Identifying the device from the access token". @@ -226,7 +232,7 @@ info: name: Apache 2.0 url: https://www.apache.org/licenses/LICENSE-2.0.html version: wip - x-camara-commonalities: 0.8.0 + x-camara-commonalities: 0.9.0 externalDocs: description: Product documentation at CAMARA @@ -261,7 +267,9 @@ paths: - `HTTP 201 (bookingStatus: TERMINATED):` The operator determined synchronously that the booking cannot be fulfilled. `statusInfo` provides the reason. - `HTTP 201 (bookingStatus: REQUESTED):` The booking resource is created and a `bookingId` is returned, but operator confirmation is still pending. A `booking-status-changed` notification will be sent to the registered `sink` with the final outcome (`SCHEDULED`, `ACTIVATED`, or `TERMINATED`). - `HTTP 4xx (Failure Condition):` The request itself was invalid. The response will include specific error codes and descriptions. + - `HTTP 422 (EVENT_NOTIFICATIONS_NOT_SUPPORTED):` A `sink` was provided but the API provider does not support event notification delivery. No booking is created; the API consumer can retry without `sink` and poll `getBookingById` instead. - `statusInfo` contains additional information under certain conditions. + - When a `sink` is provided and event delivery is accepted, `sink` is echoed in the response. operationId: createBooking parameters: - $ref: "#/components/parameters/x-correlator" @@ -301,15 +309,15 @@ paths: x-correlator: $ref: "#/components/headers/x-correlator" "400": - $ref: "#/components/responses/Generic400" + $ref: "#/components/responses/BadRequest400" "401": - $ref: "#/components/responses/Generic401" + $ref: "#/components/responses/Unauthenticated401" "403": - $ref: "#/components/responses/Generic403" + $ref: "#/components/responses/PermissionDenied403" "410": - $ref: "#/components/responses/Generic410" + $ref: "#/components/responses/SinkGone410" "429": - $ref: "#/components/responses/Generic429" + $ref: "#/components/responses/TooManyRequests429" security: - {} - notificationsBearerAuth: [] @@ -339,17 +347,17 @@ paths: BOOKING_PENDING: $ref: "#/components/examples/BOOKING_PENDING" "400": - $ref: "#/components/responses/CreateBookingOrAssign400" + $ref: "#/components/responses/CreateBooking400" "401": - $ref: "#/components/responses/Generic401" + $ref: "#/components/responses/Unauthenticated401" "403": - $ref: "#/components/responses/Generic403" + $ref: "#/components/responses/PermissionDenied403" "409": - $ref: "#/components/responses/Generic409" + $ref: "#/components/responses/AlreadyExists409" "422": - $ref: "#/components/responses/Generic422" + $ref: "#/components/responses/CreateBooking422" "429": - $ref: "#/components/responses/Generic429" + $ref: "#/components/responses/TooManyRequests429" security: - openId: - "qos-booking-and-assignment:qos-bookings:create" @@ -383,15 +391,15 @@ paths: BOOKING_RETRIEVED: $ref: "#/components/examples/BOOKING_RETRIEVED" "400": - $ref: "#/components/responses/Generic400" + $ref: "#/components/responses/BadRequest400" "401": - $ref: "#/components/responses/Generic401" + $ref: "#/components/responses/Unauthenticated401" "403": - $ref: "#/components/responses/Generic403" + $ref: "#/components/responses/PermissionDenied403" "404": - $ref: "#/components/responses/Generic404" + $ref: "#/components/responses/NotFound404" "429": - $ref: "#/components/responses/Generic429" + $ref: "#/components/responses/TooManyRequests429" security: - openId: - "qos-booking-and-assignment:qos-bookings:read" @@ -439,17 +447,17 @@ paths: CANCELLATION_PENDING: $ref: "#/components/examples/CANCELLATION_PENDING" "400": - $ref: "#/components/responses/Generic400" + $ref: "#/components/responses/BadRequest400" "401": - $ref: "#/components/responses/Generic401" + $ref: "#/components/responses/Unauthenticated401" "403": - $ref: "#/components/responses/Generic403" + $ref: "#/components/responses/PermissionDenied403" "404": - $ref: "#/components/responses/Generic404" + $ref: "#/components/responses/NotFound404" "409": - $ref: "#/components/responses/Generic409" + $ref: "#/components/responses/DeleteBooking409" "429": - $ref: "#/components/responses/Generic429" + $ref: "#/components/responses/TooManyRequests429" security: - openId: - "qos-booking-and-assignment:qos-bookings:delete" @@ -463,6 +471,8 @@ paths: This endpoint allows the end user to assign one or more devices to the existing QoS Booking. - If the assignment is successful for all the devices, the call will return 201 success code with assignmentStatus `ASSIGNED` and the network is available for the said devices to connect and use them at the requested time - If the assignment request failed for some reason, this call we be retured with 4xx error code with appropirate status codes + - If the number of devices in the request exceeds the remaining capacity of the booking (`remainingDevices`), the request is rejected with `422 QOS_BOOKING_AND_ASSIGNMENT.DEVICE_QUOTA_EXCEEDED`. The `statusInfo` value `QUOTA_EXCEEDED` is used only when the shortage is detected during asynchronous processing. + - If a `sink` is provided and the API provider does not support event notification delivery, the request is rejected with `422 EVENT_NOTIFICATIONS_NOT_SUPPORTED` and no device is assigned. - This is an asynchronous call, and assignmentStatus = `REQUESTED` if the network is still processing your request. A callback will deliver the final assignmentStatus. - If the network could not assign all the requested devices, then assignmentStatus = `PARTIAL_SUCCESS` and the `statusInfo` will have additional information. - If a 2-legged access token is used, then the device details SHOULD BE provided as part of the input, and the output will return the array of actually assigned devices. @@ -507,15 +517,15 @@ paths: x-correlator: $ref: "#/components/headers/x-correlator" "400": - $ref: "#/components/responses/Generic400" + $ref: "#/components/responses/BadRequest400" "401": - $ref: "#/components/responses/Generic401" + $ref: "#/components/responses/Unauthenticated401" "403": - $ref: "#/components/responses/Generic403" + $ref: "#/components/responses/PermissionDenied403" "410": - $ref: "#/components/responses/Generic410" + $ref: "#/components/responses/SinkGone410" "429": - $ref: "#/components/responses/Generic429" + $ref: "#/components/responses/TooManyRequests429" security: - {} - notificationsBearerAuth: [] @@ -555,19 +565,19 @@ paths: $ref: "#/components/examples/ASSIGNMENT_PENDING" "400": - $ref: "#/components/responses/CreateBookingOrAssign400" + $ref: "#/components/responses/AssignOrReleaseDevices400" "401": - $ref: "#/components/responses/Generic401" + $ref: "#/components/responses/Unauthenticated401" "403": - $ref: "#/components/responses/Generic403" + $ref: "#/components/responses/PermissionDenied403" "404": - $ref: "#/components/responses/Generic404" + $ref: "#/components/responses/DeviceAssignmentNotFound404" "409": - $ref: "#/components/responses/Generic409" + $ref: "#/components/responses/DeviceAssignment409" "422": - $ref: "#/components/responses/Generic422" + $ref: "#/components/responses/AssignDevices422" "429": - $ref: "#/components/responses/Generic429" + $ref: "#/components/responses/TooManyRequests429" security: - openId: - "qos-booking-and-assignment:qos-bookings:devices:create" @@ -607,15 +617,15 @@ paths: $ref: "#/components/examples/ASSIGNMENT_RETRIEVED_2" "400": - $ref: "#/components/responses/Generic400" + $ref: "#/components/responses/BadRequest400" "401": - $ref: "#/components/responses/Generic401" + $ref: "#/components/responses/Unauthenticated401" "403": - $ref: "#/components/responses/Generic403" + $ref: "#/components/responses/PermissionDenied403" "404": - $ref: "#/components/responses/Generic404" + $ref: "#/components/responses/NotFound404" "429": - $ref: "#/components/responses/Generic429" + $ref: "#/components/responses/TooManyRequests429" security: - openId: - "qos-booking-and-assignment:qos-bookings:devices:read" @@ -635,6 +645,7 @@ paths: - If the device is assigned using 3-legged access token: - If the device is active, then release can happen in the same way. - If the device has failed for some reason, and the device information is not known, then the device can't be released from booking. + - If a `sink` is provided and the API provider does not support event notification delivery, the request is rejected with `422 EVENT_NOTIFICATIONS_NOT_SUPPORTED` and no device is released. - This call uses the POST method to comply with the CAMARA Commonalities guidelines for sending sensitive or complex data in API calls. Since the device field may contain personally identifiable information, it should not be sent via DELETE. operationId: releaseDevices parameters: @@ -687,19 +698,19 @@ paths: ASSIGNMENT_RELEASE_PENDING: $ref: "#/components/examples/ASSIGNMENT_RELEASE_PENDING" "400": - $ref: "#/components/responses/Generic400" + $ref: "#/components/responses/AssignOrReleaseDevices400" "401": - $ref: "#/components/responses/Generic401" + $ref: "#/components/responses/Unauthenticated401" "403": - $ref: "#/components/responses/Generic403" + $ref: "#/components/responses/PermissionDenied403" "404": - $ref: "#/components/responses/Generic404" + $ref: "#/components/responses/DeviceAssignmentNotFound404" "409": - $ref: "#/components/responses/Generic409" + $ref: "#/components/responses/DeviceAssignment409" "422": - $ref: "#/components/responses/Generic422" + $ref: "#/components/responses/ReleaseDevices422" "429": - $ref: "#/components/responses/Generic429" + $ref: "#/components/responses/TooManyRequests429" security: - openId: - "qos-booking-and-assignment:qos-bookings:devices:delete" @@ -747,15 +758,15 @@ paths: RETRIEVE_BOOKINGS_NO_ITEMS: $ref: "#/components/examples/RETRIEVE_BOOKINGS_NO_ITEMS" "400": - $ref: "#/components/responses/Generic400" + $ref: "#/components/responses/BadRequest400" "401": - $ref: "#/components/responses/Generic401" + $ref: "#/components/responses/Unauthenticated401" "403": - $ref: "#/components/responses/Generic403" + $ref: "#/components/responses/PermissionDenied403" "422": - $ref: "#/components/responses/Generic422" + $ref: "#/components/responses/DeviceIdentifier422" "429": - $ref: "#/components/responses/Generic429" + $ref: "#/components/responses/TooManyRequests429" security: - openId: - "qos-booking-and-assignment:qos-bookings:retrieve-by-device" @@ -807,12 +818,7 @@ components: serviceArea: $ref: "../common/CAMARA_common.yaml#/components/schemas/Area" sink: - type: string - format: uri - maxLength: 2048 - pattern: "^https:\/\/.+$" - description: The address to which events shall be delivered, using the HTTP protocol. - example: "https://endpoint.example.com/sink" + $ref: "../common/CAMARA_event_common.yaml#/components/schemas/Sink" sinkCredential: $ref: "../common/CAMARA_event_common.yaml#/components/schemas/SinkCredential" required: @@ -859,6 +865,7 @@ components: `remainingDevices` >= 0 and <= `bookingDeviceCount` - Once a device is successfully assigned to the booking, `remainingDevices` will be reduced by 1, and once the device is released then it will be incremented by 1 - Booking Information is also returned as part of the message body when the devices are successfully assigned to the booking. + - `sink` is echoed in the `createBooking` response when it was provided in the request and event delivery is accepted by the API provider. - `bookingId` is present when `bookingStatus` is `REQUESTED`, `SCHEDULED`, or `ACTIVATED` — the booking resource exists and is addressable. It is absent when `bookingStatus` is `TERMINATED` at creation time, meaning the operator rejected the booking synchronously and no resource was created. allOf: @@ -882,6 +889,8 @@ components: $ref: "#/components/schemas/BookingStatus" statusInfo: $ref: "#/components/schemas/BookingStatusInfo" + sink: + $ref: "../common/CAMARA_event_common.yaml#/components/schemas/Sink" required: - remainingDevices - qosProfile @@ -903,12 +912,7 @@ components: devices: $ref: "#/components/schemas/Devices" sink: - type: string - format: uri - maxLength: 2048 - pattern: ^https:\/\/.+$ - description: The address to which events shall be delivered, using the HTTP protocol. - example: "https://endpoint.example.com/sink" + $ref: "../common/CAMARA_event_common.yaml#/components/schemas/Sink" sinkCredential: $ref: "../common/CAMARA_event_common.yaml#/components/schemas/SinkCredential" @@ -1192,23 +1196,30 @@ components: $ref: "../common/CAMARA_common.yaml#/components/schemas/DeviceResponse" responses: - Generic400: - $ref: "../common/CAMARA_common.yaml#/components/responses/Generic400" - Generic401: - $ref: "../common/CAMARA_common.yaml#/components/responses/Generic401" - Generic403: - $ref: "../common/CAMARA_common.yaml#/components/responses/Generic403" - Generic404: - $ref: "../common/CAMARA_common.yaml#/components/responses/Generic404" - Generic410: - $ref: "../common/CAMARA_common.yaml#/components/responses/Generic410" - Generic422: - $ref: "../common/CAMARA_common.yaml#/components/responses/Generic422" - Generic429: - $ref: "../common/CAMARA_common.yaml#/components/responses/Generic429" - - CreateBookingOrAssign400: - description: Bad Request when creating a QoS booking or assigning devices to a booking. + # Catalogue error responses provided by the Commonalities common files + BadRequest400: + $ref: "../common/CAMARA_common.yaml#/components/responses/BadRequest400" + Unauthenticated401: + $ref: "../common/CAMARA_common.yaml#/components/responses/Unauthenticated401" + PermissionDenied403: + $ref: "../common/CAMARA_common.yaml#/components/responses/PermissionDenied403" + NotFound404: + $ref: "../common/CAMARA_common.yaml#/components/responses/NotFound404" + AlreadyExists409: + $ref: "../common/CAMARA_common.yaml#/components/responses/AlreadyExists409" + DeviceIdentifier422: + $ref: "../common/CAMARA_common.yaml#/components/responses/DeviceIdentifier422" + TooManyRequests429: + $ref: "../common/CAMARA_common.yaml#/components/responses/TooManyRequests429" + SinkGone410: + $ref: "../common/CAMARA_event_common.yaml#/components/responses/SinkGone410" + + # Error responses defined locally: API-specific codes or a combination of common codes + # not covered by the catalogue. Examples for common codes reference the shared examples; + # only the QOS_BOOKING_AND_ASSIGNMENT.* examples are defined inline (components/examples). + + CreateBooking400: + description: Bad Request when creating a QoS booking. headers: x-correlator: $ref: "#/components/headers/x-correlator" @@ -1232,42 +1243,101 @@ components: - INVALID_SINK examples: GENERIC_400_INVALID_ARGUMENT: - description: Invalid Argument. Generic Syntax Exception - value: - status: 400 - code: INVALID_ARGUMENT - message: Client specified an invalid argument, request body or query param. + $ref: "../common/CAMARA_common.yaml#/components/examples/GENERIC_400_INVALID_ARGUMENT" GENERIC_400_OUT_OF_RANGE: - description: Out of Range. Specific Syntax Exception used when a given field has a pre-defined range or a invalid filter criteria combination is requested - value: - status: 400 - code: OUT_OF_RANGE - message: Client specified an invalid range. + $ref: "../common/CAMARA_common.yaml#/components/examples/GENERIC_400_OUT_OF_RANGE" DurationOutOfRangeForQoSProfile: - description: The requested duration is out of the allowed range for the specific QoS profile - value: - status: 400 - code: QOS_BOOKING_AND_ASSIGNMENT.DURATION_OUT_OF_RANGE - message: The requested duration is out of the allowed range for the specific QoS profile + $ref: "#/components/examples/DurationOutOfRangeForQoSProfile" + GENERIC_400_INVALID_CREDENTIAL: + $ref: "../common/CAMARA_event_common.yaml#/components/examples/GENERIC_400_INVALID_CREDENTIAL" + GENERIC_400_INVALID_TOKEN: + $ref: "../common/CAMARA_event_common.yaml#/components/examples/GENERIC_400_INVALID_TOKEN" + GENERIC_400_INVALID_SINK: + $ref: "../common/CAMARA_event_common.yaml#/components/examples/GENERIC_400_INVALID_SINK" + + AssignOrReleaseDevices400: + description: Bad Request when assigning devices to, or releasing devices from, a QoS booking. + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "../common/CAMARA_common.yaml#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 400 + code: + enum: + - INVALID_ARGUMENT + - OUT_OF_RANGE + - INVALID_CREDENTIAL + - INVALID_TOKEN + - INVALID_SINK + examples: + GENERIC_400_INVALID_ARGUMENT: + $ref: "../common/CAMARA_common.yaml#/components/examples/GENERIC_400_INVALID_ARGUMENT" + GENERIC_400_OUT_OF_RANGE: + $ref: "../common/CAMARA_common.yaml#/components/examples/GENERIC_400_OUT_OF_RANGE" GENERIC_400_INVALID_CREDENTIAL: - value: - status: 400 - code: INVALID_CREDENTIAL - message: Only Access token is supported + $ref: "../common/CAMARA_event_common.yaml#/components/examples/GENERIC_400_INVALID_CREDENTIAL" GENERIC_400_INVALID_TOKEN: - value: - status: 400 - code: INVALID_TOKEN - message: Only bearer token is supported + $ref: "../common/CAMARA_event_common.yaml#/components/examples/GENERIC_400_INVALID_TOKEN" GENERIC_400_INVALID_SINK: - description: Invalid sink value - value: - status: 400 - code: INVALID_SINK - message: sink not valid for the specified protocol - - Generic409: - description: Handle all conflict error conditions as per commonalities guidelines + $ref: "../common/CAMARA_event_common.yaml#/components/examples/GENERIC_400_INVALID_SINK" + + DeviceAssignmentNotFound404: + description: Not found. The booking, or a device identifier in the request, cannot be found. + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "../common/CAMARA_common.yaml#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 404 + code: + enum: + - NOT_FOUND + - IDENTIFIER_NOT_FOUND + examples: + GENERIC_404_NOT_FOUND: + $ref: "../common/CAMARA_common.yaml#/components/examples/GENERIC_404_NOT_FOUND" + GENERIC_404_IDENTIFIER_NOT_FOUND: + $ref: "../common/CAMARA_common.yaml#/components/examples/GENERIC_404_IDENTIFIER_NOT_FOUND" + + DeleteBooking409: + description: Conflict. The booking is in a state incompatible with its deletion. + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "../common/CAMARA_common.yaml#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 409 + code: + enum: + - INCOMPATIBLE_STATE + examples: + GENERIC_409_INCOMPATIBLE_STATE: + $ref: "../common/CAMARA_common.yaml#/components/examples/GENERIC_409_INCOMPATIBLE_STATE" + + DeviceAssignment409: + description: Conflict when assigning devices to, or releasing devices from, a QoS booking. headers: x-correlator: $ref: "#/components/headers/x-correlator" @@ -1284,34 +1354,105 @@ components: code: enum: - ABORTED - - ALREADY_EXISTS - - CONFLICT - INCOMPATIBLE_STATE examples: GENERIC_409_ABORTED: - description: Concurreny of processes of the same nature/scope - value: - status: 409 - code: ABORTED - message: Concurrency conflict. - GENERIC_409_ALREADY_EXISTS: - description: Trying to create an existing resource - value: - status: 409 - code: ALREADY_EXISTS - message: The resource that a client tried to create already exists. - GENERIC_409_CONFLICT: - description: Duplication of an existing resource - value: - status: 409 - code: CONFLICT - message: A specified resource duplicate entry found. + $ref: "../common/CAMARA_common.yaml#/components/examples/GENERIC_409_ABORTED" GENERIC_409_INCOMPATIBLE_STATE: - description: A resource referenced in the request is in an incompatible state for the requested operation - value: - status: 409 - code: INCOMPATIBLE_STATE - message: A referenced resource is in an incompatible state. + $ref: "../common/CAMARA_common.yaml#/components/examples/GENERIC_409_INCOMPATIBLE_STATE" + + CreateBooking422: + description: Unprocessable Content when creating a QoS booking. + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "../common/CAMARA_common.yaml#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 422 + code: + enum: + - EVENT_NOTIFICATIONS_NOT_SUPPORTED + examples: + GENERIC_422_EVENT_NOTIFICATIONS_NOT_SUPPORTED: + $ref: "../common/CAMARA_event_common.yaml#/components/examples/GENERIC_422_EVENT_NOTIFICATIONS_NOT_SUPPORTED" + + AssignDevices422: + description: Unprocessable Content when assigning devices to a QoS booking. + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "../common/CAMARA_common.yaml#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 422 + code: + enum: + - SERVICE_NOT_APPLICABLE + - MISSING_IDENTIFIER + - UNSUPPORTED_IDENTIFIER + - UNNECESSARY_IDENTIFIER + - EVENT_NOTIFICATIONS_NOT_SUPPORTED + - QOS_BOOKING_AND_ASSIGNMENT.DEVICE_QUOTA_EXCEEDED + examples: + GENERIC_422_SERVICE_NOT_APPLICABLE: + $ref: "../common/CAMARA_common.yaml#/components/examples/GENERIC_422_SERVICE_NOT_APPLICABLE" + GENERIC_422_MISSING_IDENTIFIER_DEVICE: + $ref: "../common/CAMARA_common.yaml#/components/examples/GENERIC_422_MISSING_IDENTIFIER_DEVICE" + GENERIC_422_UNSUPPORTED_IDENTIFIER_DEVICE: + $ref: "../common/CAMARA_common.yaml#/components/examples/GENERIC_422_UNSUPPORTED_IDENTIFIER_DEVICE" + GENERIC_422_UNNECESSARY_IDENTIFIER_DEVICE: + $ref: "../common/CAMARA_common.yaml#/components/examples/GENERIC_422_UNNECESSARY_IDENTIFIER_DEVICE" + GENERIC_422_EVENT_NOTIFICATIONS_NOT_SUPPORTED: + $ref: "../common/CAMARA_event_common.yaml#/components/examples/GENERIC_422_EVENT_NOTIFICATIONS_NOT_SUPPORTED" + DeviceQuotaExceededForBooking: + $ref: "#/components/examples/DeviceQuotaExceededForBooking" + + ReleaseDevices422: + description: Unprocessable Content when releasing devices from a QoS booking. + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "../common/CAMARA_common.yaml#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 422 + code: + enum: + - SERVICE_NOT_APPLICABLE + - MISSING_IDENTIFIER + - UNSUPPORTED_IDENTIFIER + - UNNECESSARY_IDENTIFIER + - EVENT_NOTIFICATIONS_NOT_SUPPORTED + examples: + GENERIC_422_SERVICE_NOT_APPLICABLE: + $ref: "../common/CAMARA_common.yaml#/components/examples/GENERIC_422_SERVICE_NOT_APPLICABLE" + GENERIC_422_MISSING_IDENTIFIER_DEVICE: + $ref: "../common/CAMARA_common.yaml#/components/examples/GENERIC_422_MISSING_IDENTIFIER_DEVICE" + GENERIC_422_UNSUPPORTED_IDENTIFIER_DEVICE: + $ref: "../common/CAMARA_common.yaml#/components/examples/GENERIC_422_UNSUPPORTED_IDENTIFIER_DEVICE" + GENERIC_422_UNNECESSARY_IDENTIFIER_DEVICE: + $ref: "../common/CAMARA_common.yaml#/components/examples/GENERIC_422_UNNECESSARY_IDENTIFIER_DEVICE" + GENERIC_422_EVENT_NOTIFICATIONS_NOT_SUPPORTED: + $ref: "../common/CAMARA_event_common.yaml#/components/examples/GENERIC_422_EVENT_NOTIFICATIONS_NOT_SUPPORTED" examples: BOOKING_INPUT_1: @@ -1728,3 +1869,19 @@ components: summary: No bookings found for the device description: No bookings are found for the device, value contains only empty array value: [] + + DurationOutOfRangeForQoSProfile: + summary: Duration out of range for the QoS profile + description: The requested duration is out of the allowed range for the specific QoS profile + value: + status: 400 + code: QOS_BOOKING_AND_ASSIGNMENT.DURATION_OUT_OF_RANGE + message: The requested duration is out of the allowed range for the specific QoS profile + + DeviceQuotaExceededForBooking: + summary: Device quota of the booking exceeded + description: The number of devices in the request exceeds the remaining device capacity of the booking + value: + status: 422 + code: QOS_BOOKING_AND_ASSIGNMENT.DEVICE_QUOTA_EXCEEDED + message: The number of devices exceeds the remaining device capacity of the booking. diff --git a/code/Test_definitions/qos-booking-and-assignment-assignDevices.feature b/code/Test_definitions/qos-booking-and-assignment-assignDevices.feature new file mode 100644 index 0000000..5dee00e --- /dev/null +++ b/code/Test_definitions/qos-booking-and-assignment-assignDevices.feature @@ -0,0 +1,479 @@ +Feature: CAMARA QoS Booking and Assignment API, vwip - Operation assignDevices + # CAMARA Commonalities: 0.9.0 + # + # Input to be provided by the implementation to the tester + # + # Implementation indications: + # * apiRoot: API root of the server URL + # * Scenarios marked as CONDITIONAL in their comments apply only if the implementation supports the option they test; the implementation informs the tester of the supported options. + # * Whether event notification delivery (sink) is supported. If not, the scenarios for 422 EVENT_NOTIFICATIONS_NOT_SUPPORTED apply. + # * Whether assignDevices is resolved synchronously (201), asynchronously (202 followed by an assignment-status-changed event) or both. + # * List of device identifier types which are not supported, among: phoneNumber, ipv4Address, ipv6Address. networkAccessIdentifier is not currently supported by this API. + # + # Testing assets: + # * A valid QoS profile name, and the maximum duration allowed for it. + # * A valid service area compliant with the Area schema. + # * At least two valid devices (device objects) applicable for the service, identified by identifier types supported by the implementation. + # * A device object identifying a device commercialized by the implementation for which the service is not applicable, if any. + # * A 2-legged access token, and a 3-legged access token identifying a single device. + # * An https endpoint able to receive CloudEvents, with a valid access token to be used as sinkCredential (credentialType ACCESSTOKEN). + # * An access token emitted to a different API client than the one that created the QoS booking. + # + # References to OAS spec schemas refer to schemas specified in qos-booking-and-assignment-wip-alignedto_r4dot4.yaml + + Background: Common "assignDevices" setup + Given an environment at "apiRoot" + And the resource "/qos-booking-and-assignment/vwip/qos-bookings/{bookingId}/devices/assign" + And the header "Content-Type" is set to "application/json" + And the header "Authorization" is set to a valid access token + And the header "x-correlator" complies with the schema at "#/components/schemas/XCorrelator" + And the path parameter "bookingId" is set by default to the identifier of an existing QoS booking created by operation "createBooking", in status "SCHEDULED" or "ACTIVATED", with remaining device capacity + And the request body is set by default to a request body compliant with the schema at "#/components/schemas/DeviceAssignmentInput" + +############################ Happy Path Scenarios ############################################# + + @qos_booking_and_assignment_assignDevices_01_generic_success_scenario + Scenario Outline: Common validations for any success scenario + Given the header "Authorization" is set to a valid 2-legged access token + And the request body property "$.devices" is set to a valid array of device identifiers compliant with the schema at "#/components/schemas/Devices" + When the request "assignDevices" is sent + 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/DeviceAssignmentOutput" + # Additionally, any success response has to comply with some constraints beyond the schema compliance + And the response property "" matches the rule: + + Examples: + | property | condition | + | $.assignmentStatus | is "ASSIGNED" | + | $.devices | exists and contains the same or a subset of the device identifiers given in the request body | + | $.bookingDetails.bookingId | same value as the path parameter "bookingId" | + | $.bookingDetails.remainingDevices | decreased by the number of assigned devices, compared with its value before the request | + + @qos_booking_and_assignment_assignDevices_02_three_legged_token + Scenario: Assign the device identified by a 3-legged access token + Given the header "Authorization" is set to a valid 3-legged access token identifying a single device + And the request body property "$.devices" is not included + When the request "assignDevices" is sent + Then the response status code is 201 + And the response body complies with the OAS schema at "#/components/schemas/DeviceAssignmentOutput" + And the response property "$.assignmentStatus" is "ASSIGNED" + And the response property "$.bookingDetails.remainingDevices" is decreased by 1 + And the response property "$.devices" may not contain the assigned device information + + @qos_booking_and_assignment_assignDevices_03_assigned_devices_listed + Scenario: Assigned devices are returned by getDevicesByBookingId + Given the header "Authorization" is set to a valid 2-legged access token + And the request body property "$.devices" is set to a valid array of device identifiers compliant with the schema at "#/components/schemas/Devices" + When the request "assignDevices" is sent + Then the response status code is 201 + When the request "getDevicesByBookingId" is sent with the same path parameter "bookingId" + Then the response status code is 200 + And the response property "$.devices" contains the device identifiers returned by the assignment response + + # CONDITIONAL: only applicable if the API provider supports partial assignment + @qos_booking_and_assignment_assignDevices_04_partial_success + Scenario: Only some of the requested devices can be assigned + Given the header "Authorization" is set to a valid 2-legged access token + And the request body property "$.devices" includes valid devices and at least one device that cannot be assigned + When the request "assignDevices" is sent + Then the response status code is 201 + And the response body complies with the OAS schema at "#/components/schemas/DeviceAssignmentOutput" + And the response property "$.assignmentStatus" is "PARTIAL_SUCCESS" + And the response property "$.statusInfo" exists + And the response property "$.devices" contains only a subset of the device identifiers given in the request body + + # CONDITIONAL: only applicable if the API provider resolves assignments asynchronously + @qos_booking_and_assignment_assignDevices_05_asynchronous_processing + Scenario: Assignment accepted for asynchronous processing + Given the header "Authorization" is set to a valid 2-legged access token + And the request body property "$.devices" is set to a valid array of device identifiers compliant with the schema at "#/components/schemas/Devices" + When the request "assignDevices" is sent + 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/DeviceAssignmentOutput" + And the response property "$.assignmentStatus" is "REQUESTED" + + # CONDITIONAL: only applicable if the API provider resolves assignments asynchronously and supports event notifications + @qos_booking_and_assignment_assignDevices_06_event_notification + Scenario: Event is received when the assignment outcome is known after using sink + Given a device assignment has been accepted for asynchronous processing (status code 202) with operation "assignDevices" + And the request included a valid sink and sinkCredentials + When the assignment outcome is known + Then an event is received at the address of the request property "$.sink" + And the event header "Authorization" is set to "Bearer " + the value of the request property "$.sinkCredential.accessToken" + And the event header "Content-Type" is set to "application/cloudevents+json" + And the event body complies with the OAS schema at "#/components/schemas/EventAssignmentStatusChanged" + And the event body property "$.id" is unique + And the event body property "$.type" is set to "org.camaraproject.qos-booking-and-assignment.v0.assignment-status-changed" + And the event body property "$.data.deviceDetails.bookingDetails.bookingId" has the same value as the path parameter "bookingId" of the request + And the event body property "$.data.assignmentStatus" is "ASSIGNED", "PARTIAL_SUCCESS" or "FAILURE" + +############################ Error Scenarios ############################################# + + # Syntax Error scenarios + + # applicable for operations with a mandatory request body + @qos_booking_and_assignment_assignDevices_400.1_no_request_body + Scenario: Missing request body + Given the request body is not included + When the request "assignDevices" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + 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 + + @qos_booking_and_assignment_assignDevices_400.2_schema_not_compliant + Scenario: Invalid Argument. Generic Syntax Exception + Given the request body is set to any value which is not compliant with the schema at "#/components/schemas/DeviceAssignmentInput" + When the request "assignDevices" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + 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 + + @qos_booking_and_assignment_assignDevices_400.3_empty_property + Scenario Outline: Error response for empty property in request body + Given the request body property "" is set to + When the request "assignDevices" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + 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: + | property | value | + | $.devices | [] | + | $.sinkCredential | {} | + + @qos_booking_and_assignment_assignDevices_400.4_invalid_booking_id + Scenario: Invalid bookingId path parameter + Given the path parameter "bookingId" is set to a value that is not a valid UUID + When the request "assignDevices" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + 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 + + @qos_booking_and_assignment_assignDevices_400.5_invalid_x-correlator + Scenario: Invalid x-correlator header + Given the header "x-correlator" does not comply with the schema at "#/components/schemas/XCorrelator" + When the request "assignDevices" 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 + + # PLAIN and REFRESHTOKEN are not valid credentialType values in the common SinkCredential schema, so a schema validator may fail + # the request with INVALID_ARGUMENT instead of INVALID_CREDENTIAL, and both could be accepted + @qos_booking_and_assignment_assignDevices_400.6_invalid_sink_credential + Scenario Outline: Invalid credential + Given the request body property "$.sinkCredential.credentialType" is set to "" + When the request "assignDevices" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 400 + And the response property "$.code" is "INVALID_CREDENTIAL" or "INVALID_ARGUMENT" + And the response property "$.message" contains a user friendly text + + Examples: + | unsupported_credential_type | + | PLAIN | + | REFRESHTOKEN | + + # Only "bearer" is considered in the schema so a generic schema validator may fail and generate a 400 INVALID_ARGUMENT without further distinction, + # and both could be accepted + @qos_booking_and_assignment_assignDevices_400.7_sink_credential_invalid_token + Scenario: Invalid token + Given the request body property "$.sinkCredential.accessTokenType" is set to a value other than "bearer" + When the request "assignDevices" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 400 + And the response property "$.code" is "INVALID_TOKEN" or "INVALID_ARGUMENT" + And the response property "$.message" contains a user friendly text + + # The sink must be an https URL. A generic schema validator may report INVALID_ARGUMENT instead of INVALID_SINK, and both could be accepted + @qos_booking_and_assignment_assignDevices_400.8_invalid_sink + Scenario Outline: Invalid sink + Given the request body property "$.sink" is set to "" + When the request "assignDevices" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 400 + And the response property "$.code" is "INVALID_SINK" or "INVALID_ARGUMENT" + And the response property "$.message" contains a user friendly text + + Examples: + | invalid_sink | + | http://endpoint.example.com/sink | + | ftp://endpoint.example.com/sink | + + # The API rejects undeclared properties (see section Request body strictness of the API description) + @qos_booking_and_assignment_assignDevices_400.9_unknown_property + Scenario: Request body contains a property not declared in the schema + Given the request body includes an undeclared property "$.unexpectedParam" set to any value + When the request "assignDevices" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + 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 + + # The maximum is considered in the schema so a generic schema validator may fail and generate a 400 INVALID_ARGUMENT without further distinction, + # and both could be accepted + @qos_booking_and_assignment_assignDevices_400.10_too_many_devices + Scenario: The devices array exceeds the maximum of 50 + Given the request body property "$.devices" is set to an array of 51 valid device identifiers compliant with the schema at "#/components/schemas/Device" + When the request "assignDevices" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 400 + And the response property "$.code" is "OUT_OF_RANGE" or "INVALID_ARGUMENT" + And the response property "$.message" contains a user friendly text + + # Service Error scenarios + + ## Authentication/Authorization errors + + # Generic 401 errors + + @qos_booking_and_assignment_assignDevices_401.1_no_authorization_header + Scenario: Error response for no header Authorization + Given the header "Authorization" is not sent + When the request "assignDevices" is sent + Then the response status code is 401 + And the response header "x-correlator" has same value as the request header "x-correlator" + 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 "$.message" contains a user friendly text + + @qos_booking_and_assignment_assignDevices_401.2_expired_access_token + Scenario: Error response for expired access token + Given the header "Authorization" is set to an expired access token + When the request "assignDevices" is sent + Then the response status code is 401 + And the response header "x-correlator" has same value as the request header "x-correlator" + 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 "$.message" contains a user friendly text + + @qos_booking_and_assignment_assignDevices_401.3_invalid_access_token + Scenario: Error response for invalid access token + Given the header "Authorization" is set to an invalid access token + When the request "assignDevices" is sent + Then the response status code is 401 + And the response header "x-correlator" has same value as the request header "x-correlator" + 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 "$.message" contains a user friendly text + + # Generic 403 errors + + @qos_booking_and_assignment_assignDevices_403.1_missing_access_token_scope + Scenario: Missing access token scope + Given the header "Authorization" is set to an access token that does not include scope "qos-booking-and-assignment:qos-bookings:devices:create" + When the request "assignDevices" is sent + Then the response status code is 403 + And the response header "x-correlator" has same value as the request header "x-correlator" + 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 + + # To test this, a token has to be obtained for a different client + @qos_booking_and_assignment_assignDevices_403.2_api_client_token_mismatch + Scenario: QoS booking not created by the API client given in the access token + Given the header "Authorization" is set to a valid access token emitted to an API client which did not create the QoS booking + When the request "assignDevices" is sent + Then the response status code is 403 + And the response header "x-correlator" has same value as the request header "x-correlator" + 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 + + # Generic 404 errors + + @qos_booking_and_assignment_assignDevices_404.1_not_found + Scenario: Non-existing "bookingId" + Given the path parameter "bookingId" is set to a random UUID that does not correspond to any existing QoS booking + When the request "assignDevices" is sent + Then the response status code is 404 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + 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 + + # Generic 409 errors + + # CONDITIONAL: only applicable if the API provider does not allow concurrent modifications of the same booking + @qos_booking_and_assignment_assignDevices_409.1_request_aborted + Scenario: Conflict due to the QoS booking being modified by a concurrent request + Given a concurrent assignment or release operation is in progress for the same QoS booking and the service does not allow concurrent modifications + When the request "assignDevices" is sent + Then the response status code is 409 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 409 + And the response property "$.code" is "ABORTED" + And the response property "$.message" contains a user friendly text + + # Devices can only be assigned to a booking in status SCHEDULED or ACTIVATED + @qos_booking_and_assignment_assignDevices_409.2_incompatible_state + Scenario: Conflict due to the QoS booking being in an incompatible state + Given the path parameter "bookingId" is set to the identifier of a QoS booking in status "TERMINATED" + When the request "assignDevices" is sent + Then the response status code is 409 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 409 + And the response property "$.code" is "INCOMPATIBLE_STATE" + And the response property "$.message" contains a user friendly text + + # Device error scenarios (Commonalities C01 - device errors) + + @qos_booking_and_assignment_assignDevices_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 "$.devices[0]" is set to: {} + When the request "assignDevices" 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 + + @qos_booking_and_assignment_assignDevices_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 "assignDevices" 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 | + | $.devices[0].phoneNumber | #/components/schemas/PhoneNumber | + | $.devices[0].ipv4Address | #/components/schemas/DeviceIpv4Address | + | $.devices[0].ipv6Address | #/components/schemas/DeviceIpv6Address | + | $.devices[0].networkAccessIdentifier | #/components/schemas/NetworkAccessIdentifier | + + # The 404 IDENTIFIER_NOT_FOUND is declared for this operation. Devices that cannot be processed once the request is accepted are reported with assignmentStatus and statusInfo (e.g. DEVICE_NOT_FOUND) + @qos_booking_and_assignment_assignDevices_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 "$.devices[0]" is compliant with the schema but does not identify a valid device + When the request "assignDevices" 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 + + @qos_booking_and_assignment_assignDevices_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 "$.devices[0]" is set to a valid device + When the request "assignDevices" 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 + + @qos_booking_and_assignment_assignDevices_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 "$.devices" is not included + When the request "assignDevices" 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 + + # CONDITIONAL: networkAccessIdentifier is not currently supported by this API, so it can be used as the unsupported identifier + @qos_booking_and_assignment_assignDevices_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 "$.devices[0]" only includes device identifiers not supported by the implementation + When the request "assignDevices" 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 + + # CONDITIONAL: only applicable when the service is offered to certain types of devices or subscriptions + @qos_booking_and_assignment_assignDevices_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 "assignDevices" 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 + + # 422 errors + + # CONDITIONAL: only applicable if the API provider does not implement event notification delivery + # The resource MUST NOT be created when the request is rejected + @qos_booking_and_assignment_assignDevices_422.1_event_notifications_not_supported + Scenario: Event notifications capability not supported + Given the request body includes property "$.sink" with a valid value + And the API provider does not implement event notifications delivery for the operation "assignDevices" + When the request "assignDevices" is sent + Then the response status code is 422 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 422 + And the response property "$.code" is "EVENT_NOTIFICATIONS_NOT_SUPPORTED" + And the response property "$.message" contains a user friendly text + + # N+1 must not exceed 50, the maximum size of the devices array + @qos_booking_and_assignment_assignDevices_422.2_device_quota_exceeded + Scenario: The number of devices exceeds the remaining capacity of the QoS booking + Given the header "Authorization" is set to a valid 2-legged access token + And the path parameter "bookingId" is set to the identifier of a QoS booking with N remaining devices + And the request body property "$.devices" is set to an array of N+1 valid device identifiers compliant with the schema at "#/components/schemas/Devices" + When the request "assignDevices" is sent + Then the response status code is 422 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 422 + And the response property "$.code" is "QOS_BOOKING_AND_ASSIGNMENT.DEVICE_QUOTA_EXCEEDED" + And the response property "$.message" contains a user friendly text + + # Generic 429 errors + + # To test this scenario the environment has to be configured to reject requests reaching the threshold limit set. + @qos_booking_and_assignment_assignDevices_429.1_too_many_requests + Scenario: Request is rejected due to threshold policy + Given a valid request for "assignDevices" + And the header "Authorization" is set to a valid access token + And the threshold of requests has been reached + When the request "assignDevices" is sent + Then the response status code is 429 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response property "$.status" is 429 + And the response property "$.code" is "TOO_MANY_REQUESTS" + And the response property "$.message" contains a user friendly text diff --git a/code/Test_definitions/qos-booking-and-assignment-createBooking.feature b/code/Test_definitions/qos-booking-and-assignment-createBooking.feature new file mode 100644 index 0000000..1bd139a --- /dev/null +++ b/code/Test_definitions/qos-booking-and-assignment-createBooking.feature @@ -0,0 +1,449 @@ +Feature: CAMARA QoS Booking and Assignment API, vwip - Operation createBooking + # CAMARA Commonalities: 0.9.0 + # + # Input to be provided by the implementation to the tester + # + # Implementation indications: + # * apiRoot: API root of the server URL + # * Scenarios marked as CONDITIONAL in their comments apply only if the implementation supports the option they test; the implementation informs the tester of the supported options. + # * Supported booking confirmation mode(s) for createBooking: synchronous (SCHEDULED or ACTIVATED in the 201 response) and/or asynchronous (REQUESTED followed by a booking-status-changed event). + # * Whether event notification delivery (sink) is supported. If not, the scenarios for 422 EVENT_NOTIFICATIONS_NOT_SUPPORTED apply. + # + # Testing assets: + # * A valid QoS profile name, and the maximum duration allowed for it. + # * A valid service area compliant with the Area schema. + # * An https endpoint able to receive CloudEvents, with a valid access token to be used as sinkCredential (credentialType ACCESSTOKEN). + # + # References to OAS spec schemas refer to schemas specified in qos-booking-and-assignment-wip-alignedto_r4dot4.yaml + + Background: Common "createBooking" setup + Given an environment at "apiRoot" + And the resource "/qos-booking-and-assignment/vwip/qos-bookings" + And the header "Content-Type" is set to "application/json" + And the header "Authorization" is set to a valid access token + And the header "x-correlator" complies with the schema at "#/components/schemas/XCorrelator" + And the request body is set by default to a request body compliant with the schema at "#/components/schemas/BookingInput" + +############################ Happy Path Scenarios ############################################# + + @qos_booking_and_assignment_createBooking_01_generic_success_scenario + Scenario Outline: Common validations for any success scenario + Given the request body property "$.qosProfile" is set to a valid QoS profile + And the request body property "$.startTime" is set to a valid time in the future + And the request body property "$.duration" is set to a valid duration for the selected QoS profile + And the request body property "$.serviceArea" is set to a valid service area compliant with the schema at "#/components/schemas/Area" + When the request "createBooking" is sent + 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/BookingOutput" + # Additionally, any success response has to comply with some constraints beyond the schema compliance + And the response property "" matches the rule: + + Examples: + | property | condition | + | $.bookingId | exists and is a valid UUID | + | $.bookingStatus | is "REQUESTED", "SCHEDULED" or "ACTIVATED" | + | $.qosProfile | same value as in the request body | + | $.startTime | same value as in the request body | + | $.duration | same value as in the request body | + | $.serviceArea | same value as in the request body | + | $.bookingDeviceCount | same value as in the request body, if provided | + | $.remainingDevices | equal to "$.bookingDeviceCount" of the request body, or to 1 if it was not provided | + | $.sink | exists only if provided in the request body and with the same value | + | $.sinkCredential | does not exist | + + @qos_booking_and_assignment_createBooking_02_all_optional_properties + Scenario: Create a QoS booking providing all optional properties + Given the request body property "$.bookingDeviceCount" is set to a valid number of devices + And the request body property "$.sink" is set to a URL where events can be monitored + And the request body property "$.sinkCredential.credentialType" is set to "ACCESSTOKEN" + And the request body property "$.sinkCredential.accessToken" is set to a valid access token accepted by the events receiver + And the request body property "$.sinkCredential.accessTokenType" is set to "bearer" + And the request body property "$.sinkCredential.accessTokenExpiresUtc" is set to a value long enough in the future + When the request "createBooking" is sent + Then the response status code is 201 + And the response body complies with the OAS schema at "#/components/schemas/BookingOutput" + And the response property "$.bookingDeviceCount" has the same value as in the request body + And the response property "$.remainingDevices" is equal to the value of "$.bookingDeviceCount" + And the response property "$.sink" has same value as the request body property "$.sink" + And the response property "$.sinkCredential" does not exist + + @qos_booking_and_assignment_createBooking_03_booking_device_count_limits + Scenario Outline: Create a QoS booking with the minimum and maximum number of devices + Given the request body property "$.bookingDeviceCount" is set to + When the request "createBooking" is sent + Then the response status code is 201 + And the response property "$.bookingDeviceCount" is + And the response property "$.remainingDevices" is + + Examples: + | count | + | 1 | + | 50 | + + # "REQUESTED" is only returned by implementations that confirm the booking asynchronously + @qos_booking_and_assignment_createBooking_04_future_start_time + Scenario: Booking with a start time in the future + Given the request body property "$.startTime" is set to a valid time in the future + When the request "createBooking" is sent + Then the response status code is 201 + And the response property "$.bookingStatus" is "SCHEDULED" or "REQUESTED" + + # "REQUESTED" is only returned by implementations that confirm the booking asynchronously + @qos_booking_and_assignment_createBooking_05_immediate_start_time + Scenario: Booking with a start time of now or in the past + Given the request body property "$.startTime" is set to the current time or to a time in the past + When the request "createBooking" is sent + Then the response status code is 201 + And the response property "$.bookingStatus" is "ACTIVATED" or "REQUESTED" + + # CONDITIONAL: only applicable if the API provider rejects unfulfillable bookings synchronously (e.g. SERVICE_NOT_AVAILABLE) + @qos_booking_and_assignment_createBooking_06_synchronous_rejection + Scenario: Booking that the operator cannot fulfil is terminated synchronously + Given the API provider can determine synchronously that the booking cannot be fulfilled + And the request body is compliant with the schema at "#/components/schemas/BookingInput" and requests a booking that cannot be fulfilled + When the request "createBooking" is sent + Then the response status code is 201 + And the response body complies with the OAS schema at "#/components/schemas/BookingOutput" + And the response property "$.bookingStatus" is "TERMINATED" + And the response property "$.statusInfo" exists + And the response property "$.bookingId" does not exist + + @qos_booking_and_assignment_createBooking_07_sink_echoed + Scenario: Sink is returned in the creation response when event delivery is accepted + Given the request body includes property "$.sink" with a valid value + When the request "createBooking" is sent + Then the response status code is 201 + And the response property "$.sink" has same value as the request body property "$.sink" + + @qos_booking_and_assignment_createBooking_08_booking_readable_after_creation + Scenario: The created booking can be read with getBookingById + Given the request body is compliant with the schema at "#/components/schemas/BookingInput" + When the request "createBooking" is sent + Then the response status code is 201 + And the response property "$.bookingId" exists and is a valid UUID + When the request "getBookingById" is sent with the path parameter "bookingId" set to the value of "$.bookingId" of the creation response + Then the response status code is 200 + And the response property "$.bookingId" has the same value as in the creation response + And the response property "$.qosProfile" has the same value as in the creation request body + And the response property "$.startTime" has the same value as in the creation request body + And the response property "$.duration" has the same value as in the creation request body + And the response property "$.serviceArea" has the same value as in the creation request body + + @qos_booking_and_assignment_createBooking_09_event_notification + Scenario: Event is received when a booking status changes after using sink + Given a QoS booking has been created successfully with operation "createBooking" and includes a valid sink and sinkCredentials + When the booking status changes (confirmation of a booking created with status REQUESTED, start time reached, or termination) + Then an event is received at the address of the request property "$.sink" + And the event header "Authorization" is set to "Bearer " + the value of the request property "$.sinkCredential.accessToken" + And the event header "Content-Type" is set to "application/cloudevents+json" + And the event body complies with the OAS schema at "#/components/schemas/EventBookingStatusChanged" + And the event body property "$.id" is unique + And the event body property "$.type" is set to "org.camaraproject.qos-booking-and-assignment.v0.booking-status-changed" + And the event body property "$.data.bookingDetails.bookingId" has the same value as createBooking response property "$.bookingId" + And the event body property "$.data.bookingStatus" is "SCHEDULED", "ACTIVATED" or "TERMINATED" + +############################ Error Scenarios ############################################# + + # Syntax Error scenarios + + # applicable for operations with a mandatory request body + @qos_booking_and_assignment_createBooking_400.1_no_request_body + Scenario: Missing request body + Given the request body is not included + When the request "createBooking" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + 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 + + @qos_booking_and_assignment_createBooking_400.2_schema_not_compliant + Scenario: Invalid Argument. Generic Syntax Exception + Given the request body is set to any value which is not compliant with the schema at "#/components/schemas/BookingInput" + When the request "createBooking" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + 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 + + # The request body has required properties (qosProfile, startTime, duration, serviceArea) + @qos_booking_and_assignment_createBooking_400.3_empty_request_body + Scenario: Empty object as request body + Given the request body is set to {} + When the request "createBooking" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + 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 + + # applicable to properties in the request body which are of type object and have required properties in their value + @qos_booking_and_assignment_createBooking_400.4_empty_property + Scenario Outline: Error response for empty property in request body + Given the request body property "" is set to {} + When the request "createBooking" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + 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: + | required_property | + | $.serviceArea | + | $.sinkCredential | + + @qos_booking_and_assignment_createBooking_400.5_missing_required_property + Scenario Outline: Error response for missing required property in request body + Given the request body property "" is not included + When the request "createBooking" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + 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: + | required_property | + | $.qosProfile | + | $.startTime | + | $.duration | + | $.serviceArea | + + # "2030-10-27T15:00:00" has no time zone; "ab" is shorter than the minimum length of qosProfile; "invalid profile!" has characters not allowed by its pattern + @qos_booking_and_assignment_createBooking_400.6_invalid_property_value + Scenario Outline: Error response for property values not compliant with the schema + Given the request body property "" is set to + When the request "createBooking" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + 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: + | property | value | + | $.startTime | "not-a-date-time" | + | $.startTime | "2030-10-27T15:00:00" | + | $.qosProfile | "ab" | + | $.qosProfile | "invalid profile!" | + | $.duration | "one hour" | + | $.bookingDeviceCount | "five" | + + @qos_booking_and_assignment_createBooking_400.7_invalid_x-correlator + Scenario: Invalid x-correlator header + Given the header "x-correlator" does not comply with the schema at "#/components/schemas/XCorrelator" + When the request "createBooking" 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 + + # PLAIN and REFRESHTOKEN are not valid credentialType values in the common SinkCredential schema, so a schema validator may fail + # the request with INVALID_ARGUMENT instead of INVALID_CREDENTIAL, and both could be accepted + @qos_booking_and_assignment_createBooking_400.8_invalid_sink_credential + Scenario Outline: Invalid credential + Given the request body property "$.sinkCredential.credentialType" is set to "" + When the request "createBooking" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 400 + And the response property "$.code" is "INVALID_CREDENTIAL" or "INVALID_ARGUMENT" + And the response property "$.message" contains a user friendly text + + Examples: + | unsupported_credential_type | + | PLAIN | + | REFRESHTOKEN | + + # Only "bearer" is considered in the schema so a generic schema validator may fail and generate a 400 INVALID_ARGUMENT without further distinction, + # and both could be accepted + @qos_booking_and_assignment_createBooking_400.9_sink_credential_invalid_token + Scenario: Invalid token + Given the request body property "$.sinkCredential.accessTokenType" is set to a value other than "bearer" + When the request "createBooking" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 400 + And the response property "$.code" is "INVALID_TOKEN" or "INVALID_ARGUMENT" + And the response property "$.message" contains a user friendly text + + # The sink must be an https URL. A generic schema validator may report INVALID_ARGUMENT instead of INVALID_SINK, and both could be accepted + @qos_booking_and_assignment_createBooking_400.10_invalid_sink + Scenario Outline: Invalid sink + Given the request body property "$.sink" is set to "" + When the request "createBooking" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 400 + And the response property "$.code" is "INVALID_SINK" or "INVALID_ARGUMENT" + And the response property "$.message" contains a user friendly text + + Examples: + | invalid_sink | + | http://endpoint.example.com/sink | + | ftp://endpoint.example.com/sink | + + # The API rejects undeclared properties (see section Request body strictness of the API description) + @qos_booking_and_assignment_createBooking_400.11_unknown_property + Scenario: Request body contains a property not declared in the schema + Given the request body includes an undeclared property "$.unexpectedParam" set to any value + When the request "createBooking" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + 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 + + # bookingDeviceCount is limited to the range 1 to 50, duration has a minimum of 1 second + # The maximum is considered in the schema so a generic schema validator may fail and generate a 400 INVALID_ARGUMENT without further distinction, + # and both could be accepted + @qos_booking_and_assignment_createBooking_400.12_out_of_range + Scenario Outline: Numeric property out of its declared range + Given the request body property "" is set to + When the request "createBooking" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 400 + And the response property "$.code" is "OUT_OF_RANGE" or "INVALID_ARGUMENT" + And the response property "$.message" contains a user friendly text + + Examples: + | property | value | + | $.bookingDeviceCount | 0 | + | $.bookingDeviceCount | 51 | + | $.duration | 0 | + + @qos_booking_and_assignment_createBooking_400.13_duration_out_of_range_for_qos_profile + Scenario: Duration exceeds the maximum allowed by the selected QoS profile + Given the request body property "$.qosProfile" is set to a valid QoS profile + And the request body property "$.duration" is set to a value greater than the maximum duration allowed for the selected QoS profile + When the request "createBooking" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 400 + And the response property "$.code" is "QOS_BOOKING_AND_ASSIGNMENT.DURATION_OUT_OF_RANGE" + And the response property "$.message" contains a user friendly text + + @qos_booking_and_assignment_createBooking_400.14_non_existent_qos_profile + Scenario: Error response for non-existent QoS profile in request body + Given the request body property "$.qosProfile" is set to a non-existent QoS profile + When the request "createBooking" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + 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 + + # Service Error scenarios + + ## Authentication/Authorization errors + + # Generic 401 errors + + @qos_booking_and_assignment_createBooking_401.1_no_authorization_header + Scenario: Error response for no header Authorization + Given the header "Authorization" is not sent + When the request "createBooking" is sent + Then the response status code is 401 + And the response header "x-correlator" has same value as the request header "x-correlator" + 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 "$.message" contains a user friendly text + + @qos_booking_and_assignment_createBooking_401.2_expired_access_token + Scenario: Error response for expired access token + Given the header "Authorization" is set to an expired access token + When the request "createBooking" is sent + Then the response status code is 401 + And the response header "x-correlator" has same value as the request header "x-correlator" + 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 "$.message" contains a user friendly text + + @qos_booking_and_assignment_createBooking_401.3_invalid_access_token + Scenario: Error response for invalid access token + Given the header "Authorization" is set to an invalid access token + When the request "createBooking" is sent + Then the response status code is 401 + And the response header "x-correlator" has same value as the request header "x-correlator" + 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 "$.message" contains a user friendly text + + # Generic 403 errors + + @qos_booking_and_assignment_createBooking_403.1_missing_access_token_scope + Scenario: Missing access token scope + Given the header "Authorization" is set to an access token that does not include scope "qos-booking-and-assignment:qos-bookings:create" + When the request "createBooking" is sent + Then the response status code is 403 + And the response header "x-correlator" has same value as the request header "x-correlator" + 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 + + # Generic 409 errors + + @qos_booking_and_assignment_createBooking_409.1_duplicated_booking + Scenario: Conflict due to an existing identical QoS booking + Given a QoS booking already exists, created by the same API client, with identical parameters to the ones in the request body + And the request body is set to the same values used to create that QoS booking + When the request "createBooking" is sent + Then the response status code is 409 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 409 + And the response property "$.code" is "ALREADY_EXISTS" + And the response property "$.message" contains a user friendly text + + # 422 errors + + # CONDITIONAL: only applicable if the API provider does not implement event notification delivery + # The resource MUST NOT be created when the request is rejected + @qos_booking_and_assignment_createBooking_422.1_event_notifications_not_supported + Scenario: Event notifications capability not supported + Given the request body includes property "$.sink" with a valid value + And the API provider does not implement event notifications delivery for the operation "createBooking" + When the request "createBooking" is sent + Then the response status code is 422 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 422 + And the response property "$.code" is "EVENT_NOTIFICATIONS_NOT_SUPPORTED" + And the response property "$.message" contains a user friendly text + + # Generic 429 errors + + # To test this scenario the environment has to be configured to reject requests reaching the threshold limit set. + @qos_booking_and_assignment_createBooking_429.1_too_many_requests + Scenario: Request is rejected due to threshold policy + Given a valid request for "createBooking" + And the header "Authorization" is set to a valid access token + And the threshold of requests has been reached + When the request "createBooking" is sent + Then the response status code is 429 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response property "$.status" is 429 + And the response property "$.code" is "TOO_MANY_REQUESTS" + And the response property "$.message" contains a user friendly text diff --git a/code/Test_definitions/qos-booking-and-assignment-deleteBooking.feature b/code/Test_definitions/qos-booking-and-assignment-deleteBooking.feature new file mode 100644 index 0000000..186ccbb --- /dev/null +++ b/code/Test_definitions/qos-booking-and-assignment-deleteBooking.feature @@ -0,0 +1,211 @@ +Feature: CAMARA QoS Booking and Assignment API, vwip - Operation deleteBooking + # CAMARA Commonalities: 0.9.0 + # + # Input to be provided by the implementation to the tester + # + # Implementation indications: + # * apiRoot: API root of the server URL + # * Scenarios marked as CONDITIONAL in their comments apply only if the implementation supports the option they test; the implementation informs the tester of the supported options. + # * Supported booking confirmation mode(s) for createBooking: synchronous (SCHEDULED or ACTIVATED in the 201 response) and/or asynchronous (REQUESTED followed by a booking-status-changed event). + # * Whether deleteBooking is processed synchronously (204), asynchronously (202) or both. + # * Whether deleteBooking is rejected with 409 INCOMPATIBLE_STATE while devices remain assigned, or releases them automatically. + # + # Testing assets: + # * A valid QoS profile name, and the maximum duration allowed for it. + # * A valid service area compliant with the Area schema. + # * An https endpoint able to receive CloudEvents, with a valid access token to be used as sinkCredential (credentialType ACCESSTOKEN). + # * An access token emitted to a different API client than the one that created the QoS booking. + # + # References to OAS spec schemas refer to schemas specified in qos-booking-and-assignment-wip-alignedto_r4dot4.yaml + + Background: Common "deleteBooking" setup + Given an environment at "apiRoot" + And the resource "/qos-booking-and-assignment/vwip/qos-bookings/{bookingId}" + And the header "Authorization" is set to a valid access token + And the header "x-correlator" complies with the schema at "#/components/schemas/XCorrelator" + And the path parameter "bookingId" is set by default to the identifier of an existing QoS booking created by operation "createBooking" + +############################ Happy Path Scenarios ############################################# + + # CONDITIONAL: only applicable if the API provider processes the deletion synchronously + @qos_booking_and_assignment_deleteBooking_01_sync_success_scenario + Scenario: Delete a QoS booking processed synchronously + Given an existing QoS booking created by operation "createBooking" with no devices assigned + And the path parameter "bookingId" is set to the value of the identifier for that QoS booking + When the request "deleteBooking" is sent + Then the response status code is 204 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response body is empty + + # CONDITIONAL: only applicable if the API provider processes the deletion asynchronously + @qos_booking_and_assignment_deleteBooking_02_async_success_scenario + Scenario: Delete a QoS booking processed asynchronously + Given an existing QoS booking created by operation "createBooking" with no devices assigned + And the path parameter "bookingId" is set to the value of the identifier for that QoS booking + When the request "deleteBooking" is sent + 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/BookingOutput" + And the response property "$.bookingId" has the same value as the path parameter "bookingId" + And the response property "$.bookingStatus" is "REQUESTED" + And the response property "$.statusInfo" is "DELETE_REQUESTED" + + # CONDITIONAL: applicable if the API provider processes the deletion synchronously. For asynchronous processing the check applies once the cancellation event has been received + @qos_booking_and_assignment_deleteBooking_03_booking_not_readable_after_deletion + Scenario: A deleted QoS booking can no longer be read + Given an existing QoS booking created by operation "createBooking" with no devices assigned + And the path parameter "bookingId" is set to the value of the identifier for that QoS booking + When the request "deleteBooking" is sent + Then the response status code is 204 + When the request "getBookingById" is sent with the same path parameter "bookingId" + 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 + + @qos_booking_and_assignment_deleteBooking_04_event_notification + Scenario: Cancellation event is received after using sink + Given a QoS booking has been created successfully with operation "createBooking" and includes a valid sink and sinkCredentials + And its deletion has been requested successfully with operation "deleteBooking" + When the booking cancellation is completed + Then an event is received at the address of the request property "$.sink" + And the event header "Authorization" is set to "Bearer " + the value of the request property "$.sinkCredential.accessToken" + And the event header "Content-Type" is set to "application/cloudevents+json" + And the event body complies with the OAS schema at "#/components/schemas/EventBookingStatusChanged" + And the event body property "$.id" is unique + And the event body property "$.type" is set to "org.camaraproject.qos-booking-and-assignment.v0.booking-status-changed" + And the event body property "$.data.bookingDetails.bookingId" has the same value as createBooking response property "$.bookingId" + And the event body property "$.data.bookingStatus" is "TERMINATED" + And the event body property "$.data.statusInfo" is "BOOKING_CANCELLED" + +############################ Error Scenarios ############################################# + + # Syntax Error scenarios + + @qos_booking_and_assignment_deleteBooking_400.1_invalid_booking_id + Scenario: Invalid bookingId path parameter + Given the path parameter "bookingId" is set to a value that is not a valid UUID + When the request "deleteBooking" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + 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 + + @qos_booking_and_assignment_deleteBooking_400.2_invalid_x-correlator + Scenario: Invalid x-correlator header + Given the header "x-correlator" does not comply with the schema at "#/components/schemas/XCorrelator" + When the request "deleteBooking" 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 + + # Service Error scenarios + + ## Authentication/Authorization errors + + # Generic 401 errors + + @qos_booking_and_assignment_deleteBooking_401.1_no_authorization_header + Scenario: Error response for no header Authorization + Given the header "Authorization" is not sent + When the request "deleteBooking" is sent + Then the response status code is 401 + And the response header "x-correlator" has same value as the request header "x-correlator" + 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 "$.message" contains a user friendly text + + @qos_booking_and_assignment_deleteBooking_401.2_expired_access_token + Scenario: Error response for expired access token + Given the header "Authorization" is set to an expired access token + When the request "deleteBooking" is sent + Then the response status code is 401 + And the response header "x-correlator" has same value as the request header "x-correlator" + 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 "$.message" contains a user friendly text + + @qos_booking_and_assignment_deleteBooking_401.3_invalid_access_token + Scenario: Error response for invalid access token + Given the header "Authorization" is set to an invalid access token + When the request "deleteBooking" is sent + Then the response status code is 401 + And the response header "x-correlator" has same value as the request header "x-correlator" + 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 "$.message" contains a user friendly text + + # Generic 403 errors + + @qos_booking_and_assignment_deleteBooking_403.1_missing_access_token_scope + Scenario: Missing access token scope + Given the header "Authorization" is set to an access token that does not include scope "qos-booking-and-assignment:qos-bookings:delete" + When the request "deleteBooking" is sent + Then the response status code is 403 + And the response header "x-correlator" has same value as the request header "x-correlator" + 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 + + # To test this, a token has to be obtained for a different client + @qos_booking_and_assignment_deleteBooking_403.2_api_client_token_mismatch + Scenario: QoS booking not created by the API client given in the access token + Given the header "Authorization" is set to a valid access token emitted to an API client which did not create the QoS booking + When the request "deleteBooking" is sent + Then the response status code is 403 + And the response header "x-correlator" has same value as the request header "x-correlator" + 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 + + # Generic 404 errors + + @qos_booking_and_assignment_deleteBooking_404.1_not_found + Scenario: Non-existing "bookingId" + Given the path parameter "bookingId" is set to a random UUID that does not correspond to any existing QoS booking + When the request "deleteBooking" is sent + Then the response status code is 404 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + 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 + + # Generic 409 errors + + # CONDITIONAL: only applicable if the API provider rejects the deletion of bookings with assigned devices (provider-dependent, see the deleteBooking description) + @qos_booking_and_assignment_deleteBooking_409.1_incompatible_state + Scenario: Conflict due to devices still assigned to the QoS booking + Given an existing QoS booking created by operation "createBooking" with at least one device assigned by operation "assignDevices" + And the path parameter "bookingId" is set to the value of the identifier for that QoS booking + When the request "deleteBooking" is sent + Then the response status code is 409 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 409 + And the response property "$.code" is "INCOMPATIBLE_STATE" + And the response property "$.message" contains a user friendly text + + # Generic 429 errors + + # To test this scenario the environment has to be configured to reject requests reaching the threshold limit set. + @qos_booking_and_assignment_deleteBooking_429.1_too_many_requests + Scenario: Request is rejected due to threshold policy + Given a valid request for "deleteBooking" + And the header "Authorization" is set to a valid access token + And the threshold of requests has been reached + When the request "deleteBooking" is sent + Then the response status code is 429 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response property "$.status" is 429 + And the response property "$.code" is "TOO_MANY_REQUESTS" + And the response property "$.message" contains a user friendly text diff --git a/code/Test_definitions/qos-booking-and-assignment-getBookingById.feature b/code/Test_definitions/qos-booking-and-assignment-getBookingById.feature new file mode 100644 index 0000000..11693fe --- /dev/null +++ b/code/Test_definitions/qos-booking-and-assignment-getBookingById.feature @@ -0,0 +1,177 @@ +Feature: CAMARA QoS Booking and Assignment API, vwip - Operation getBookingById + # CAMARA Commonalities: 0.9.0 + # + # Input to be provided by the implementation to the tester + # + # Implementation indications: + # * apiRoot: API root of the server URL + # * Scenarios marked as CONDITIONAL in their comments apply only if the implementation supports the option they test; the implementation informs the tester of the supported options. + # * Supported booking confirmation mode(s) for createBooking: synchronous (SCHEDULED or ACTIVATED in the 201 response) and/or asynchronous (REQUESTED followed by a booking-status-changed event). + # + # Testing assets: + # * A valid QoS profile name, and the maximum duration allowed for it. + # * A valid service area compliant with the Area schema. + # * An access token emitted to a different API client than the one that created the QoS booking. + # + # References to OAS spec schemas refer to schemas specified in qos-booking-and-assignment-wip-alignedto_r4dot4.yaml + + Background: Common "getBookingById" setup + Given an environment at "apiRoot" + And the resource "/qos-booking-and-assignment/vwip/qos-bookings/{bookingId}" + And the header "Authorization" is set to a valid access token + And the header "x-correlator" complies with the schema at "#/components/schemas/XCorrelator" + And the path parameter "bookingId" is set by default to the identifier of an existing QoS booking created by operation "createBooking" + +############################ Happy Path Scenarios ############################################# + + @qos_booking_and_assignment_getBookingById_01_generic_success_scenario + Scenario Outline: Common validations for any success scenario + Given an existing QoS booking created by operation "createBooking" + And the path parameter "bookingId" is set to the value of the identifier for that QoS booking + When the request "getBookingById" 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/BookingOutput" + # Additionally, any success response has to comply with some constraints beyond the schema compliance + And the response property "" matches the rule: + + Examples: + | property | condition | + | $.bookingId | same value as the path parameter "bookingId" | + | $.bookingStatus | is "REQUESTED", "SCHEDULED", "ACTIVATED" or "TERMINATED" | + | $.remainingDevices | a number greater than or equal to 0 and less than or equal to "$.bookingDeviceCount" | + | $.qosProfile | same value as in the request body used for createBooking | + | $.startTime | same value as in the request body used for createBooking | + | $.duration | same value as in the request body used for createBooking | + | $.serviceArea | same value as in the request body used for createBooking | + + @qos_booking_and_assignment_getBookingById_02_remaining_devices_after_assignment + Scenario Outline: remainingDevices reflects the devices assigned to the booking + Given an existing QoS booking with "$.bookingDeviceCount" devices created by operation "createBooking" + And devices have been assigned to it by operation "assignDevices" + When the request "getBookingById" is sent + Then the response status code is 200 + And the response property "$.bookingDeviceCount" is the number of devices requested at creation + And the response property "$.remainingDevices" is equal to "$.bookingDeviceCount" minus + + Examples: + | assigned | + | 1 | + | 2 | + +############################ Error Scenarios ############################################# + + # Syntax Error scenarios + + @qos_booking_and_assignment_getBookingById_400.1_invalid_booking_id + Scenario: Invalid bookingId path parameter + Given the path parameter "bookingId" is set to a value that is not a valid UUID + When the request "getBookingById" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + 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 + + @qos_booking_and_assignment_getBookingById_400.2_invalid_x-correlator + Scenario: Invalid x-correlator header + Given the header "x-correlator" does not comply with the schema at "#/components/schemas/XCorrelator" + When the request "getBookingById" 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 + + # Service Error scenarios + + ## Authentication/Authorization errors + + # Generic 401 errors + + @qos_booking_and_assignment_getBookingById_401.1_no_authorization_header + Scenario: Error response for no header Authorization + Given the header "Authorization" is not sent + When the request "getBookingById" is sent + Then the response status code is 401 + And the response header "x-correlator" has same value as the request header "x-correlator" + 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 "$.message" contains a user friendly text + + @qos_booking_and_assignment_getBookingById_401.2_expired_access_token + Scenario: Error response for expired access token + Given the header "Authorization" is set to an expired access token + When the request "getBookingById" is sent + Then the response status code is 401 + And the response header "x-correlator" has same value as the request header "x-correlator" + 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 "$.message" contains a user friendly text + + @qos_booking_and_assignment_getBookingById_401.3_invalid_access_token + Scenario: Error response for invalid access token + Given the header "Authorization" is set to an invalid access token + When the request "getBookingById" is sent + Then the response status code is 401 + And the response header "x-correlator" has same value as the request header "x-correlator" + 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 "$.message" contains a user friendly text + + # Generic 403 errors + + @qos_booking_and_assignment_getBookingById_403.1_missing_access_token_scope + Scenario: Missing access token scope + Given the header "Authorization" is set to an access token that does not include scope "qos-booking-and-assignment:qos-bookings:read" + When the request "getBookingById" is sent + Then the response status code is 403 + And the response header "x-correlator" has same value as the request header "x-correlator" + 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 + + # To test this, a token has to be obtained for a different client + @qos_booking_and_assignment_getBookingById_403.2_api_client_token_mismatch + Scenario: QoS booking not created by the API client given in the access token + Given the header "Authorization" is set to a valid access token emitted to an API client which did not create the QoS booking + When the request "getBookingById" is sent + Then the response status code is 403 + And the response header "x-correlator" has same value as the request header "x-correlator" + 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 + + # Generic 404 errors + + @qos_booking_and_assignment_getBookingById_404.1_not_found + Scenario: Non-existing "bookingId" + Given the path parameter "bookingId" is set to a random UUID that does not correspond to any existing QoS booking + When the request "getBookingById" is sent + Then the response status code is 404 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + 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 + + # Generic 429 errors + + # To test this scenario the environment has to be configured to reject requests reaching the threshold limit set. + @qos_booking_and_assignment_getBookingById_429.1_too_many_requests + Scenario: Request is rejected due to threshold policy + Given a valid request for "getBookingById" + And the header "Authorization" is set to a valid access token + And the threshold of requests has been reached + When the request "getBookingById" is sent + Then the response status code is 429 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response property "$.status" is 429 + And the response property "$.code" is "TOO_MANY_REQUESTS" + And the response property "$.message" contains a user friendly text diff --git a/code/Test_definitions/qos-booking-and-assignment-getDevicesByBookingId.feature b/code/Test_definitions/qos-booking-and-assignment-getDevicesByBookingId.feature new file mode 100644 index 0000000..105fd22 --- /dev/null +++ b/code/Test_definitions/qos-booking-and-assignment-getDevicesByBookingId.feature @@ -0,0 +1,173 @@ +Feature: CAMARA QoS Booking and Assignment API, vwip - Operation getDevicesByBookingId + # CAMARA Commonalities: 0.9.0 + # + # Input to be provided by the implementation to the tester + # + # Implementation indications: + # * apiRoot: API root of the server URL + # * Scenarios marked as CONDITIONAL in their comments apply only if the implementation supports the option they test; the implementation informs the tester of the supported options. + # + # Testing assets: + # * A valid QoS profile name, and the maximum duration allowed for it. + # * A valid service area compliant with the Area schema. + # * At least two valid devices (device objects) applicable for the service, identified by identifier types supported by the implementation. + # * A device object identifying a device commercialized by the implementation for which the service is not applicable, if any. + # * A 2-legged access token, and a 3-legged access token identifying a single device. + # * An access token emitted to a different API client than the one that created the QoS booking. + # + # References to OAS spec schemas refer to schemas specified in qos-booking-and-assignment-wip-alignedto_r4dot4.yaml + + Background: Common "getDevicesByBookingId" setup + Given an environment at "apiRoot" + And the resource "/qos-booking-and-assignment/vwip/qos-bookings/{bookingId}/devices" + And the header "Authorization" is set to a valid access token + And the header "x-correlator" complies with the schema at "#/components/schemas/XCorrelator" + And the path parameter "bookingId" is set by default to the identifier of an existing QoS booking created by operation "createBooking" with devices assigned by operation "assignDevices" + +############################ Happy Path Scenarios ############################################# + + @qos_booking_and_assignment_getDevicesByBookingId_01_generic_success_scenario + Scenario Outline: Common validations for any success scenario + Given an existing QoS booking with devices assigned by operation "assignDevices" + And the path parameter "bookingId" is set to the value of the identifier for that QoS booking + When the request "getDevicesByBookingId" 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/DeviceAssignmentOutput" + # Additionally, any success response has to comply with some constraints beyond the schema compliance + And the response property "" matches the rule: + + Examples: + | property | condition | + | $.assignmentStatus | is "ASSIGNED" | + | $.bookingDetails.bookingId | same value as the path parameter "bookingId" | + | $.devices | contains one or more device identifiers set originally during "assignDevices" | + + # CONDITIONAL: only applicable if the API provider withholds device identifiers under a disclosure policy + @qos_booking_and_assignment_getDevicesByBookingId_02_device_disclosure_policy_applied + Scenario: Device identifiers are withheld due to privacy or legal requirements + Given an existing QoS booking with devices assigned, some of which cannot be disclosed due to privacy or legal requirements + And the path parameter "bookingId" is set to the value of the identifier for that QoS booking + When the request "getDevicesByBookingId" is sent + Then the response status code is 200 + And the response body complies with the OAS schema at "#/components/schemas/DeviceAssignmentOutput" + And the response property "$.statusInfo" is "DEVICE_DISCLOSURE_POLICY_APPLIED" + And the number of device identifiers in "$.devices" is lower than the number of devices assigned to the booking + And the number of devices assigned to the booking is the difference between "$.bookingDetails.bookingDeviceCount" and "$.bookingDetails.remainingDevices" + +############################ Error Scenarios ############################################# + + # Syntax Error scenarios + + @qos_booking_and_assignment_getDevicesByBookingId_400.1_invalid_booking_id + Scenario: Invalid bookingId path parameter + Given the path parameter "bookingId" is set to a value that is not a valid UUID + When the request "getDevicesByBookingId" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + 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 + + @qos_booking_and_assignment_getDevicesByBookingId_400.2_invalid_x-correlator + Scenario: Invalid x-correlator header + Given the header "x-correlator" does not comply with the schema at "#/components/schemas/XCorrelator" + When the request "getDevicesByBookingId" 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 + + # Service Error scenarios + + ## Authentication/Authorization errors + + # Generic 401 errors + + @qos_booking_and_assignment_getDevicesByBookingId_401.1_no_authorization_header + Scenario: Error response for no header Authorization + Given the header "Authorization" is not sent + When the request "getDevicesByBookingId" is sent + Then the response status code is 401 + And the response header "x-correlator" has same value as the request header "x-correlator" + 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 "$.message" contains a user friendly text + + @qos_booking_and_assignment_getDevicesByBookingId_401.2_expired_access_token + Scenario: Error response for expired access token + Given the header "Authorization" is set to an expired access token + When the request "getDevicesByBookingId" is sent + Then the response status code is 401 + And the response header "x-correlator" has same value as the request header "x-correlator" + 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 "$.message" contains a user friendly text + + @qos_booking_and_assignment_getDevicesByBookingId_401.3_invalid_access_token + Scenario: Error response for invalid access token + Given the header "Authorization" is set to an invalid access token + When the request "getDevicesByBookingId" is sent + Then the response status code is 401 + And the response header "x-correlator" has same value as the request header "x-correlator" + 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 "$.message" contains a user friendly text + + # Generic 403 errors + + @qos_booking_and_assignment_getDevicesByBookingId_403.1_missing_access_token_scope + Scenario: Missing access token scope + Given the header "Authorization" is set to an access token that does not include scope "qos-booking-and-assignment:qos-bookings:devices:read" + When the request "getDevicesByBookingId" is sent + Then the response status code is 403 + And the response header "x-correlator" has same value as the request header "x-correlator" + 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 + + # To test this, a token has to be obtained for a different client + @qos_booking_and_assignment_getDevicesByBookingId_403.2_api_client_token_mismatch + Scenario: QoS booking not created by the API client given in the access token + Given the header "Authorization" is set to a valid access token emitted to an API client which did not create the QoS booking + When the request "getDevicesByBookingId" is sent + Then the response status code is 403 + And the response header "x-correlator" has same value as the request header "x-correlator" + 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 + + # Generic 404 errors + + @qos_booking_and_assignment_getDevicesByBookingId_404.1_not_found + Scenario: Non-existing "bookingId" + Given the path parameter "bookingId" is set to a random UUID that does not correspond to any existing QoS booking + When the request "getDevicesByBookingId" is sent + Then the response status code is 404 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + 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 + + # Generic 429 errors + + # To test this scenario the environment has to be configured to reject requests reaching the threshold limit set. + @qos_booking_and_assignment_getDevicesByBookingId_429.1_too_many_requests + Scenario: Request is rejected due to threshold policy + Given a valid request for "getDevicesByBookingId" + And the header "Authorization" is set to a valid access token + And the threshold of requests has been reached + When the request "getDevicesByBookingId" is sent + Then the response status code is 429 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response property "$.status" is 429 + And the response property "$.code" is "TOO_MANY_REQUESTS" + And the response property "$.message" contains a user friendly text diff --git a/code/Test_definitions/qos-booking-and-assignment-releaseDevices.feature b/code/Test_definitions/qos-booking-and-assignment-releaseDevices.feature new file mode 100644 index 0000000..6c8c74e --- /dev/null +++ b/code/Test_definitions/qos-booking-and-assignment-releaseDevices.feature @@ -0,0 +1,463 @@ +Feature: CAMARA QoS Booking and Assignment API, vwip - Operation releaseDevices + # CAMARA Commonalities: 0.9.0 + # + # Input to be provided by the implementation to the tester + # + # Implementation indications: + # * apiRoot: API root of the server URL + # * Scenarios marked as CONDITIONAL in their comments apply only if the implementation supports the option they test; the implementation informs the tester of the supported options. + # * Whether event notification delivery (sink) is supported. If not, the scenarios for 422 EVENT_NOTIFICATIONS_NOT_SUPPORTED apply. + # * Whether releaseDevices is resolved synchronously (200), asynchronously (202 followed by an assignment-status-changed event) or both. + # * List of device identifier types which are not supported, among: phoneNumber, ipv4Address, ipv6Address. networkAccessIdentifier is not currently supported by this API. + # + # Testing assets: + # * A valid QoS profile name, and the maximum duration allowed for it. + # * A valid service area compliant with the Area schema. + # * At least two valid devices (device objects) applicable for the service, identified by identifier types supported by the implementation. + # * A device object identifying a device commercialized by the implementation for which the service is not applicable, if any. + # * A 2-legged access token, and a 3-legged access token identifying a single device. + # * An https endpoint able to receive CloudEvents, with a valid access token to be used as sinkCredential (credentialType ACCESSTOKEN). + # * An access token emitted to a different API client than the one that created the QoS booking. + # + # References to OAS spec schemas refer to schemas specified in qos-booking-and-assignment-wip-alignedto_r4dot4.yaml + + Background: Common "releaseDevices" setup + Given an environment at "apiRoot" + And the resource "/qos-booking-and-assignment/vwip/qos-bookings/{bookingId}/devices/release" + And the header "Content-Type" is set to "application/json" + And the header "Authorization" is set to a valid access token + And the header "x-correlator" complies with the schema at "#/components/schemas/XCorrelator" + And the path parameter "bookingId" is set by default to the identifier of an existing QoS booking created by operation "createBooking" with devices assigned by operation "assignDevices" + And the request body is set by default to a request body compliant with the schema at "#/components/schemas/DeviceAssignmentInput" + +############################ Happy Path Scenarios ############################################# + + @qos_booking_and_assignment_releaseDevices_01_generic_success_scenario + Scenario Outline: Common validations for any success scenario + Given the header "Authorization" is set to a valid 2-legged access token + And the request body property "$.devices" is set to a valid array of device identifiers that are assigned to the QoS booking + When the request "releaseDevices" 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/DeviceAssignmentOutput" + # Additionally, any success response has to comply with some constraints beyond the schema compliance + And the response property "" matches the rule: + + Examples: + | property | condition | + | $.assignmentStatus | is "RELEASED" | + | $.devices | contains the device identifiers released from the QoS booking | + | $.bookingDetails.bookingId | same value as the path parameter "bookingId" | + | $.bookingDetails.remainingDevices | increased by the number of released devices, compared with its value before the request | + + @qos_booking_and_assignment_releaseDevices_02_three_legged_token + Scenario: Release the device identified by a 3-legged access token + Given the header "Authorization" is set to a valid 3-legged access token identifying a single device assigned to the QoS booking + And the request body property "$.devices" is not included + When the request "releaseDevices" is sent + Then the response status code is 200 + And the response body complies with the OAS schema at "#/components/schemas/DeviceAssignmentOutput" + And the response property "$.assignmentStatus" is "RELEASED" + And the response property "$.bookingDetails.remainingDevices" is increased by 1 + + @qos_booking_and_assignment_releaseDevices_03_released_devices_not_listed + Scenario: Released devices are no longer returned by getDevicesByBookingId + Given the header "Authorization" is set to a valid 2-legged access token + And the request body property "$.devices" is set to a valid array of device identifiers that are assigned to the QoS booking + When the request "releaseDevices" is sent + Then the response status code is 200 + When the request "getDevicesByBookingId" is sent with the same path parameter "bookingId" + Then the response status code is 200 + And the response property "$.devices" does not contain any of the released device identifiers + + # CONDITIONAL: only applicable if the API provider supports partial release + @qos_booking_and_assignment_releaseDevices_04_partial_success + Scenario: Only some of the requested devices can be released + Given the header "Authorization" is set to a valid 2-legged access token + And the request body property "$.devices" includes devices assigned to the QoS booking and at least one device that cannot be released + When the request "releaseDevices" is sent + Then the response status code is 200 + And the response body complies with the OAS schema at "#/components/schemas/DeviceAssignmentOutput" + And the response property "$.assignmentStatus" is "PARTIAL_SUCCESS" + And the response property "$.statusInfo" exists + And the response property "$.devices" contains only the device identifiers that were released + + # CONDITIONAL: only applicable if the API provider resolves releases asynchronously + @qos_booking_and_assignment_releaseDevices_05_asynchronous_processing + Scenario: Release accepted for asynchronous processing + Given the header "Authorization" is set to a valid 2-legged access token + And the request body property "$.devices" is set to a valid array of device identifiers that are assigned to the QoS booking + When the request "releaseDevices" is sent + 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/DeviceAssignmentOutput" + And the response property "$.assignmentStatus" is "REQUESTED" + + # CONDITIONAL: only applicable if the API provider resolves releases asynchronously and supports event notifications + @qos_booking_and_assignment_releaseDevices_06_event_notification + Scenario: Event is received when the release outcome is known after using sink + Given a device release has been accepted for asynchronous processing (status code 202) with operation "releaseDevices" + And the request included a valid sink and sinkCredentials + When the release outcome is known + Then an event is received at the address of the request property "$.sink" + And the event header "Authorization" is set to "Bearer " + the value of the request property "$.sinkCredential.accessToken" + And the event header "Content-Type" is set to "application/cloudevents+json" + And the event body complies with the OAS schema at "#/components/schemas/EventAssignmentStatusChanged" + And the event body property "$.id" is unique + And the event body property "$.type" is set to "org.camaraproject.qos-booking-and-assignment.v0.assignment-status-changed" + And the event body property "$.data.deviceDetails.bookingDetails.bookingId" has the same value as the path parameter "bookingId" of the request + And the event body property "$.data.assignmentStatus" is "RELEASED", "PARTIAL_SUCCESS" or "FAILURE" + +############################ Error Scenarios ############################################# + + # Syntax Error scenarios + + # applicable for operations with a mandatory request body + @qos_booking_and_assignment_releaseDevices_400.1_no_request_body + Scenario: Missing request body + Given the request body is not included + When the request "releaseDevices" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + 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 + + @qos_booking_and_assignment_releaseDevices_400.2_schema_not_compliant + Scenario: Invalid Argument. Generic Syntax Exception + Given the request body is set to any value which is not compliant with the schema at "#/components/schemas/DeviceAssignmentInput" + When the request "releaseDevices" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + 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 + + @qos_booking_and_assignment_releaseDevices_400.3_empty_property + Scenario Outline: Error response for empty property in request body + Given the request body property "" is set to + When the request "releaseDevices" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + 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: + | property | value | + | $.devices | [] | + | $.sinkCredential | {} | + + @qos_booking_and_assignment_releaseDevices_400.4_invalid_booking_id + Scenario: Invalid bookingId path parameter + Given the path parameter "bookingId" is set to a value that is not a valid UUID + When the request "releaseDevices" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + 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 + + @qos_booking_and_assignment_releaseDevices_400.5_invalid_x-correlator + Scenario: Invalid x-correlator header + Given the header "x-correlator" does not comply with the schema at "#/components/schemas/XCorrelator" + When the request "releaseDevices" 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 + + # PLAIN and REFRESHTOKEN are not valid credentialType values in the common SinkCredential schema, so a schema validator may fail + # the request with INVALID_ARGUMENT instead of INVALID_CREDENTIAL, and both could be accepted + @qos_booking_and_assignment_releaseDevices_400.6_invalid_sink_credential + Scenario Outline: Invalid credential + Given the request body property "$.sinkCredential.credentialType" is set to "" + When the request "releaseDevices" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 400 + And the response property "$.code" is "INVALID_CREDENTIAL" or "INVALID_ARGUMENT" + And the response property "$.message" contains a user friendly text + + Examples: + | unsupported_credential_type | + | PLAIN | + | REFRESHTOKEN | + + # Only "bearer" is considered in the schema so a generic schema validator may fail and generate a 400 INVALID_ARGUMENT without further distinction, + # and both could be accepted + @qos_booking_and_assignment_releaseDevices_400.7_sink_credential_invalid_token + Scenario: Invalid token + Given the request body property "$.sinkCredential.accessTokenType" is set to a value other than "bearer" + When the request "releaseDevices" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 400 + And the response property "$.code" is "INVALID_TOKEN" or "INVALID_ARGUMENT" + And the response property "$.message" contains a user friendly text + + # The sink must be an https URL. A generic schema validator may report INVALID_ARGUMENT instead of INVALID_SINK, and both could be accepted + @qos_booking_and_assignment_releaseDevices_400.8_invalid_sink + Scenario Outline: Invalid sink + Given the request body property "$.sink" is set to "" + When the request "releaseDevices" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 400 + And the response property "$.code" is "INVALID_SINK" or "INVALID_ARGUMENT" + And the response property "$.message" contains a user friendly text + + Examples: + | invalid_sink | + | http://endpoint.example.com/sink | + | ftp://endpoint.example.com/sink | + + # The API rejects undeclared properties (see section Request body strictness of the API description) + @qos_booking_and_assignment_releaseDevices_400.9_unknown_property + Scenario: Request body contains a property not declared in the schema + Given the request body includes an undeclared property "$.unexpectedParam" set to any value + When the request "releaseDevices" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + 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 + + # The maximum is considered in the schema so a generic schema validator may fail and generate a 400 INVALID_ARGUMENT without further distinction, + # and both could be accepted + @qos_booking_and_assignment_releaseDevices_400.10_too_many_devices + Scenario: The devices array exceeds the maximum of 50 + Given the request body property "$.devices" is set to an array of 51 valid device identifiers compliant with the schema at "#/components/schemas/Device" + When the request "releaseDevices" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 400 + And the response property "$.code" is "OUT_OF_RANGE" or "INVALID_ARGUMENT" + And the response property "$.message" contains a user friendly text + + # Service Error scenarios + + ## Authentication/Authorization errors + + # Generic 401 errors + + @qos_booking_and_assignment_releaseDevices_401.1_no_authorization_header + Scenario: Error response for no header Authorization + Given the header "Authorization" is not sent + When the request "releaseDevices" is sent + Then the response status code is 401 + And the response header "x-correlator" has same value as the request header "x-correlator" + 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 "$.message" contains a user friendly text + + @qos_booking_and_assignment_releaseDevices_401.2_expired_access_token + Scenario: Error response for expired access token + Given the header "Authorization" is set to an expired access token + When the request "releaseDevices" is sent + Then the response status code is 401 + And the response header "x-correlator" has same value as the request header "x-correlator" + 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 "$.message" contains a user friendly text + + @qos_booking_and_assignment_releaseDevices_401.3_invalid_access_token + Scenario: Error response for invalid access token + Given the header "Authorization" is set to an invalid access token + When the request "releaseDevices" is sent + Then the response status code is 401 + And the response header "x-correlator" has same value as the request header "x-correlator" + 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 "$.message" contains a user friendly text + + # Generic 403 errors + + @qos_booking_and_assignment_releaseDevices_403.1_missing_access_token_scope + Scenario: Missing access token scope + Given the header "Authorization" is set to an access token that does not include scope "qos-booking-and-assignment:qos-bookings:devices:delete" + When the request "releaseDevices" is sent + Then the response status code is 403 + And the response header "x-correlator" has same value as the request header "x-correlator" + 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 + + # To test this, a token has to be obtained for a different client + @qos_booking_and_assignment_releaseDevices_403.2_api_client_token_mismatch + Scenario: QoS booking not created by the API client given in the access token + Given the header "Authorization" is set to a valid access token emitted to an API client which did not create the QoS booking + When the request "releaseDevices" is sent + Then the response status code is 403 + And the response header "x-correlator" has same value as the request header "x-correlator" + 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 + + # Generic 404 errors + + @qos_booking_and_assignment_releaseDevices_404.1_not_found + Scenario: Non-existing "bookingId" + Given the path parameter "bookingId" is set to a random UUID that does not correspond to any existing QoS booking + When the request "releaseDevices" is sent + Then the response status code is 404 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + 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 + + # Generic 409 errors + + # CONDITIONAL: only applicable if the API provider does not allow concurrent modifications of the same booking + @qos_booking_and_assignment_releaseDevices_409.1_request_aborted + Scenario: Conflict due to the QoS booking being modified by a concurrent request + Given a concurrent assignment or release operation is in progress for the same QoS booking and the service does not allow concurrent modifications + When the request "releaseDevices" is sent + Then the response status code is 409 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 409 + And the response property "$.code" is "ABORTED" + And the response property "$.message" contains a user friendly text + + @qos_booking_and_assignment_releaseDevices_409.2_incompatible_state + Scenario: Conflict due to the QoS booking being in an incompatible state + Given the path parameter "bookingId" is set to the identifier of a QoS booking in status "TERMINATED" + When the request "releaseDevices" is sent + Then the response status code is 409 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 409 + And the response property "$.code" is "INCOMPATIBLE_STATE" + And the response property "$.message" contains a user friendly text + + # Device error scenarios (Commonalities C01 - device errors) + + @qos_booking_and_assignment_releaseDevices_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 "$.devices[0]" is set to: {} + When the request "releaseDevices" 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 + + @qos_booking_and_assignment_releaseDevices_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 "releaseDevices" 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 | + | $.devices[0].phoneNumber | #/components/schemas/PhoneNumber | + | $.devices[0].ipv4Address | #/components/schemas/DeviceIpv4Address | + | $.devices[0].ipv6Address | #/components/schemas/DeviceIpv6Address | + | $.devices[0].networkAccessIdentifier | #/components/schemas/NetworkAccessIdentifier | + + # The 404 IDENTIFIER_NOT_FOUND is declared for this operation. Devices that cannot be processed once the request is accepted are reported with assignmentStatus and statusInfo (e.g. DEVICE_NOT_FOUND) + @qos_booking_and_assignment_releaseDevices_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 "$.devices[0]" is compliant with the schema but does not identify a valid device + When the request "releaseDevices" 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 + + @qos_booking_and_assignment_releaseDevices_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 "$.devices[0]" is set to a valid device + When the request "releaseDevices" 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 + + @qos_booking_and_assignment_releaseDevices_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 "$.devices" is not included + When the request "releaseDevices" 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 + + # CONDITIONAL: networkAccessIdentifier is not currently supported by this API, so it can be used as the unsupported identifier + @qos_booking_and_assignment_releaseDevices_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 "$.devices[0]" only includes device identifiers not supported by the implementation + When the request "releaseDevices" 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 + + # CONDITIONAL: only applicable when the service is offered to certain types of devices or subscriptions + @qos_booking_and_assignment_releaseDevices_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 "releaseDevices" 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 + + # 422 errors + + # CONDITIONAL: only applicable if the API provider does not implement event notification delivery + # The resource MUST NOT be created when the request is rejected + @qos_booking_and_assignment_releaseDevices_422.1_event_notifications_not_supported + Scenario: Event notifications capability not supported + Given the request body includes property "$.sink" with a valid value + And the API provider does not implement event notifications delivery for the operation "releaseDevices" + When the request "releaseDevices" is sent + Then the response status code is 422 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 422 + And the response property "$.code" is "EVENT_NOTIFICATIONS_NOT_SUPPORTED" + And the response property "$.message" contains a user friendly text + + # Generic 429 errors + + # To test this scenario the environment has to be configured to reject requests reaching the threshold limit set. + @qos_booking_and_assignment_releaseDevices_429.1_too_many_requests + Scenario: Request is rejected due to threshold policy + Given a valid request for "releaseDevices" + And the header "Authorization" is set to a valid access token + And the threshold of requests has been reached + When the request "releaseDevices" is sent + Then the response status code is 429 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response property "$.status" is 429 + And the response property "$.code" is "TOO_MANY_REQUESTS" + And the response property "$.message" contains a user friendly text diff --git a/code/Test_definitions/qos-booking-and-assignment-retrieveBookingByDevice.feature b/code/Test_definitions/qos-booking-and-assignment-retrieveBookingByDevice.feature new file mode 100644 index 0000000..79ca190 --- /dev/null +++ b/code/Test_definitions/qos-booking-and-assignment-retrieveBookingByDevice.feature @@ -0,0 +1,263 @@ +Feature: CAMARA QoS Booking and Assignment API, vwip - Operation retrieveBookingByDevice + # CAMARA Commonalities: 0.9.0 + # + # Input to be provided by the implementation to the tester + # + # Implementation indications: + # * apiRoot: API root of the server URL + # * Scenarios marked as CONDITIONAL in their comments apply only if the implementation supports the option they test; the implementation informs the tester of the supported options. + # * Supported booking confirmation mode(s) for createBooking: synchronous (SCHEDULED or ACTIVATED in the 201 response) and/or asynchronous (REQUESTED followed by a booking-status-changed event). + # * List of device identifier types which are not supported, among: phoneNumber, ipv4Address, ipv6Address. networkAccessIdentifier is not currently supported by this API. + # + # Testing assets: + # * A valid QoS profile name, and the maximum duration allowed for it. + # * A valid service area compliant with the Area schema. + # * At least two valid devices (device objects) applicable for the service, identified by identifier types supported by the implementation. + # * A device object identifying a device commercialized by the implementation for which the service is not applicable, if any. + # * A 2-legged access token, and a 3-legged access token identifying a single device. + # * A device with no QoS booking. + # + # References to OAS spec schemas refer to schemas specified in qos-booking-and-assignment-wip-alignedto_r4dot4.yaml + + Background: Common "retrieveBookingByDevice" setup + Given an environment at "apiRoot" + And the resource "/qos-booking-and-assignment/vwip/qos-bookings/retrieve" + And the header "Content-Type" is set to "application/json" + And the header "Authorization" is set to a valid access token + And the header "x-correlator" complies with the schema at "#/components/schemas/XCorrelator" + And the request body is set by default to a request body compliant with the schema at "#/components/schemas/RetrieveBookingByDevice" + +############################ Happy Path Scenarios ############################################# + + @qos_booking_and_assignment_retrieveBookingByDevice_01_generic_success_scenario + Scenario: Get the QoS bookings of a device using a 2-legged access token + Given the header "Authorization" is set to a valid 2-legged access token + And a valid testing device with an existing QoS booking created by operation "createBooking" and assigned by operation "assignDevices" + And the request body property "$.device" is set to that device + When the request "retrieveBookingByDevice" 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/RetrieveBookingsOutput" + And the response body is a non-empty array of items compliant with the OAS schema at "#/components/schemas/BookingDetails" + And the response property "$[0].bookingId" exists and is a valid UUID + And the response property "$[0].qosProfile" has the value provided for createBooking + And the response property "$[0].startTime" has the value provided for createBooking + And the response property "$[0].duration" has the value provided for createBooking + And the response property "$[0].serviceArea" has the value provided for createBooking + + @qos_booking_and_assignment_retrieveBookingByDevice_02_three_legged_token + Scenario: Get the QoS bookings of the device identified by a 3-legged access token + Given the header "Authorization" is set to a valid 3-legged access token identifying a device with an existing QoS booking + And the request body property "$.device" is not included + When the request "retrieveBookingByDevice" is sent + Then the response status code is 200 + And the response body complies with the OAS schema at "#/components/schemas/RetrieveBookingsOutput" + And the response body is a non-empty array of items compliant with the OAS schema at "#/components/schemas/BookingDetails" + + @qos_booking_and_assignment_retrieveBookingByDevice_03_no_bookings_for_device + Scenario: No QoS bookings exist for the device + Given the header "Authorization" is set to a valid 2-legged access token + And the request body property "$.device" is set to a valid device with no QoS booking + When the request "retrieveBookingByDevice" 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 is an empty array "[]" + + @qos_booking_and_assignment_retrieveBookingByDevice_04_multiple_bookings_for_device + Scenario: Several QoS bookings exist for the device + Given the header "Authorization" is set to a valid 2-legged access token + And a valid testing device assigned to at least two QoS bookings created by operation "createBooking" + And the request body property "$.device" is set to that device + When the request "retrieveBookingByDevice" is sent + Then the response status code is 200 + And the response body is an array with at least two items compliant with the OAS schema at "#/components/schemas/BookingDetails" + And the response body contains the "bookingId" of each of those QoS bookings + +############################ Error Scenarios ############################################# + + # Syntax Error scenarios + + # applicable for operations with a mandatory request body + @qos_booking_and_assignment_retrieveBookingByDevice_400.1_no_request_body + Scenario: Missing request body + Given the request body is not included + When the request "retrieveBookingByDevice" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + 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 + + @qos_booking_and_assignment_retrieveBookingByDevice_400.2_schema_not_compliant + Scenario: Invalid Argument. Generic Syntax Exception + Given the request body is set to any value which is not compliant with the schema at "#/components/schemas/RetrieveBookingByDevice" + When the request "retrieveBookingByDevice" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + 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 + + @qos_booking_and_assignment_retrieveBookingByDevice_400.3_invalid_x-correlator + Scenario: Invalid x-correlator header + Given the header "x-correlator" does not comply with the schema at "#/components/schemas/XCorrelator" + When the request "retrieveBookingByDevice" 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 + + # The API rejects undeclared properties (see section Request body strictness of the API description) + @qos_booking_and_assignment_retrieveBookingByDevice_400.4_unknown_property + Scenario: Request body contains a property not declared in the schema + Given the request body includes an undeclared property "$.unexpectedParam" set to any value + When the request "retrieveBookingByDevice" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + 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 + + # Service Error scenarios + + ## Authentication/Authorization errors + + # Generic 401 errors + + @qos_booking_and_assignment_retrieveBookingByDevice_401.1_no_authorization_header + Scenario: Error response for no header Authorization + Given the header "Authorization" is not sent + When the request "retrieveBookingByDevice" is sent + Then the response status code is 401 + And the response header "x-correlator" has same value as the request header "x-correlator" + 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 "$.message" contains a user friendly text + + @qos_booking_and_assignment_retrieveBookingByDevice_401.2_expired_access_token + Scenario: Error response for expired access token + Given the header "Authorization" is set to an expired access token + When the request "retrieveBookingByDevice" is sent + Then the response status code is 401 + And the response header "x-correlator" has same value as the request header "x-correlator" + 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 "$.message" contains a user friendly text + + @qos_booking_and_assignment_retrieveBookingByDevice_401.3_invalid_access_token + Scenario: Error response for invalid access token + Given the header "Authorization" is set to an invalid access token + When the request "retrieveBookingByDevice" is sent + Then the response status code is 401 + And the response header "x-correlator" has same value as the request header "x-correlator" + 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 "$.message" contains a user friendly text + + # Generic 403 errors + + @qos_booking_and_assignment_retrieveBookingByDevice_403.1_missing_access_token_scope + Scenario: Missing access token scope + Given the header "Authorization" is set to an access token that does not include scope "qos-booking-and-assignment:qos-bookings:retrieve-by-device" + When the request "retrieveBookingByDevice" is sent + Then the response status code is 403 + And the response header "x-correlator" has same value as the request header "x-correlator" + 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 + + # Device error scenarios (Commonalities C01 - device errors) + + @qos_booking_and_assignment_retrieveBookingByDevice_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 "retrieveBookingByDevice" 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 + + @qos_booking_and_assignment_retrieveBookingByDevice_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 "retrieveBookingByDevice" 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/DeviceIpv4Address | + | $.device.ipv6Address | #/components/schemas/DeviceIpv6Address | + | $.device.networkAccessIdentifier | #/components/schemas/NetworkAccessIdentifier | + + @qos_booking_and_assignment_retrieveBookingByDevice_C01.03_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 + When the request "retrieveBookingByDevice" 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 + + @qos_booking_and_assignment_retrieveBookingByDevice_C01.04_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 "retrieveBookingByDevice" 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 + + # CONDITIONAL: networkAccessIdentifier is not currently supported by this API, so it can be used as the unsupported identifier + @qos_booking_and_assignment_retrieveBookingByDevice_C01.05_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 "retrieveBookingByDevice" 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 + + # CONDITIONAL: only applicable when the service is offered to certain types of devices or subscriptions + @qos_booking_and_assignment_retrieveBookingByDevice_C01.06_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 "retrieveBookingByDevice" is sent + Then the response status code is 422 + And the response property "$.status" is 422 + And the response property "$.code" is "SERVICE_NOT_APPLICABLE" + And the response property "$.message" contains a user friendly text + + # Generic 429 errors + + # To test this scenario the environment has to be configured to reject requests reaching the threshold limit set. + @qos_booking_and_assignment_retrieveBookingByDevice_429.1_too_many_requests + Scenario: Request is rejected due to threshold policy + Given a valid request for "retrieveBookingByDevice" + And the header "Authorization" is set to a valid access token + And the threshold of requests has been reached + When the request "retrieveBookingByDevice" is sent + Then the response status code is 429 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response property "$.status" is 429 + And the response property "$.code" is "TOO_MANY_REQUESTS" + And the response property "$.message" contains a user friendly text diff --git a/code/Test_definitions/qos-booking-and-assignment.feature b/code/Test_definitions/qos-booking-and-assignment.feature deleted file mode 100644 index 6e577b1..0000000 --- a/code/Test_definitions/qos-booking-and-assignment.feature +++ /dev/null @@ -1,267 +0,0 @@ -Feature: CAMARA QoS Booking and Assignment, vwip - # Input to be provided by the implementation to the tester - # - # Implementation indications: - # * apiRoot: API root of the server URL - # References to OAS spec schemas refer to schemas specified in qos-booking-and-assignment.yaml - - Background: Common QoS Booking setup - Given an environment at "apiRoot" - And the header "Authorization" is set to a valid access token - And the header "x-correlator" complies with the schema at "#/components/schemas/XCorrelator" - - # Success scenarios for POST /qos-bookings - # Reserve a set of devices for a given qos profile, service area, scheduled future time and duration - @qos_bookings_createBooking_201_success - Scenario: Create a QoS booking with valid parameters - Given the resource "/qos-booking-and-assignment/vwip/qos-bookings" - And the header "Content-Type" is set to "application/json" - And the operationId is "createBooking" - And the request body is set to a request body compliant with the schema at "/components/schemas/BookingInput" - And the request body property "$.numDevices" is set to a valid number of devices - And the request body property "$.qosProfile" is set to a valid QoS Profile as returned by QoS Profiles API - And the request body property "$.startTime" is set to a valid time - And the request body property "$.duration" is set to a valid duration for the selected QoS profile - And the request body property "$.serviceArea" is set to a valid service area compliant with schema at "/components/schemas/Area" - And the request body property "$.sink" is set to a valid notification URL - And the request body property "$.sinkCredential.credentialType" is set to a value compliant with schema at "/components/schemas/SinkCredential" - When the request "createBooking" is sent - Then the response status code is 201 - And the response body property "$.bookingId" exists and is a valid UUID - And the response body property "$.status" is set to a value "SUCCESSFUL" - - @qos_bookings_createBooking_201_success_echo - Scenario: Create booking echoes selected request fields in response - Given the resource "/qos-booking-and-assignment/vwip/qos-bookings" - And the operationId is "createBooking" - And the request body is set to a request body compliant with the schema at "/components/schemas/BookingInput" - And the request body property "$.qosProfile" is set to a valid QoS Profile as returned by QoS Profiles API - And the request body property "$.startTime" is set to a valid time - And the request body property "$.duration" is set to a valid duration for the selected QoS profile - And the request body property "$.serviceArea" is set to a valid service area compliant with schema at "/components/schemas/Area" - And the request body property "$.sink" is set to a valid notification URL - When the request "createBooking" is sent - Then the response status code is 201 - And the response body property "$.qosProfile" has the same value as in the request body - And the response body property "$.startTime" has the same value as in the request body - And the response body property "$.duration" has the same value as in the request body - And the response body property "$.serviceArea" has the same value as in the request body - And the response body property "$.sink" exists only if provided in the request body and with the same value - - # Success scenarios for GET /qos-bookings/{bookingId} - # Given a bookingID, this GET operation gets the details of the original booking - @qos_bookings_getBookingById_200_success - Scenario: Get an existing QoS booking by bookingId - Given the resource "/qos-booking-and-assignment/vwip/qos-bookings" - And an existing QoS booking with "bookingId" is created by the operation "createBooking" - And the operationId is "getBookingById" - When the request "getBookingById" 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 the same value as the request header "x-correlator" - And the response body complies with the OAS schema at "/components/schemas/BookingOutput" - And the response body property "$.bookingId" exists and is a valid UUID - And the response body property "$.totalDevices" has the same value "$.numDevices" as in the request body - And the response body property "$.remainingDevices" is set to a valid number greater than or equal to 0 and should be less than or equal to "$.totalDevices" - And the response body property "$.startTime" has the same value as in the request body - And the response body property "$.serviceArea" has the same value as in the request body - And the response body property "$.status" is set to a value compliant with schema at "/components/schemas/Status" - And the response body property "$.status" is set to a value "SUCCESSFUL" - - # Success scenarios for DELETE /qos-bookings/{bookingId} - # This operation deletes a booking identified by bookingID. - @qos_bookings_deleteBooking_200_success - Scenario: Delete a QoS booking - Given the resource "/qos-booking-and-assignment/vwip/qos-bookings" - And "bookingId" is created by operation "createBooking" - And the operationId is "deleteBooking" - When the request "deleteBooking" 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 the same value as the request header "x-correlator" - And the response body complies with the OAS schema at "/components/schemas/BookingOutput" - And the response body property "$.bookingId" exists and is a valid UUID - And the response body property "$.totalDevices" has the same value "$.numDevices" as in the request body - And the response body property "$.remainingDevices" is set to a valid number greater than or equal to 0 and should be less than or equal to "$.totalDevices" - And the response body property "$.status" is set to a value "SUCCESSFUL" - - # Success scenarios for POST /qos-bookings/{bookingId}/devices/assign - # This operation assigns set of devices to a booking. - @devices_assignDevices_201_success - Scenario: Assign a set of devices to a QoS booking - Given the resource "/qos-booking-and-assignment/vwip/qos-bookings/{bookingId}/devices/assign" - And the "bookingId" is created by operation "createBooking" - And the operationId is "assignDevices" - And the request body complies with the OAS schema at "/components/schemas/DeviceAssignmentInput" - And the request body property "$.devices" is set to a valid array of device identifiers set to a value compliant with schema at "/components/schemas/Devices" - And the request body property "$.sink" is set to a valid notification URL - And the request body property "$.sinkCredential.credentialType" is set to a value compliant with schema at "/components/schemas/SinkCredential" - When the request "assignDevices" is sent - Then the response status code is 201 - And the response header "Content-Type" is "application/json" - And the response header "x-correlator" has the same value as the request header "x-correlator" - And the response body complies with the OAS schema at "/components/schemas/DeviceAssignmentOutput" - And the response body property "$.devices" exists and should have atleast one device identifier a value compliant with schema at "/components/schemas/Devices" - And the response body property "$.devices" should contain the same or the subset of the device identifiers given in the request body - And the response body property "$.status" is set to a value "SUCCESSFUL" - - # Success scenarios for POST qos-bookings/{bookingId}/devices/release - # This operation releases a set of devices from a booking which are already assigned to the booking - @devices_releaseDevices_200_success - Scenario: Release one or more of already assigned devices from a QoS booking - Given the resource "/qos-booking-and-assignment/vwip/qos-bookings/{bookingId}/devices/release" - And the "bookingId" is created by operation "createBooking" - And the operationId is "releaseDevices" - And the request body complies with the OAS schema at "/components/schemas/DeviceAssignmentInput" - And the request body property "$.devices" is set to a valid array of device identifiers set to a value compliant with schema at "/components/schemas/Devices" - And the request body property "$.sink" is set to a valid notification URL - And the request body property "$.sinkCredential.credentialType" is set to a value compliant with schema at "/components/schemas/SinkCredential" - When the request "releaseDevices" 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 the same value as the request header "x-correlator" - And the response body complies with the OAS schema at "/components/schemas/DeviceAssignmentOutput" - And the response body property "$.devices" is set to a value compliant with schema at "/components/schemas/Devices" - And the response body property "$.status" is set to a value "SUCCESSFUL" - - # Success scenarios for GET /qos-bookings/{bookingId}/devices - # This operation gets the list of devices assigned to a booking - @devices_getDevicesByBookingId_200_success - Scenario: Get a list of devices assigned to a QoS booking - Given the resource "/qos-booking-and-assignment/vwip/qos-bookings/{bookingId}/devices" - And the "bookingId" is created by operation "createBooking" - And the operationId is "getDevicesByBookingId" - When the request "getDevicesByBookingId" 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 the same value as the request header "x-correlator" - And the response body complies with the OAS schema at "/components/schemas/DeviceAssignmentOutput" - And the response body property "$.devices" is set to a value compliant with schema at "/components/schemas/Devices" - And the response body property "$.devices" may contain one or more device identifiers set originally during "assignDevices" - And the response body property "$.status" is set to a value "SUCCESSFUL" - - # Success scenarios for POST /qos-bookings/retrieve - @devices_retrieveBooking_200_success - Scenario: Get QoS Booking resource information details for a device - Given a valid testing device with an existing QoS Booking, identified by the token or provided in the request body - And the resource "/qos-booking-and-assignment/vwip/qos-bookings/retrieve" - When the request "retrieveBookingByDevice" 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 the same value as the request header "x-correlator" - And the response body complies with the OAS schema at "/components/schemas/RetrieveBookingsOutput" - # Additionally any success response has to comply with some constraints beyond the schema compliance - And the response body is a non-empty array of items compliant with the OAS schema at "/components/schemas/BookingDetails" - And the response body property "$[0].bookingId" exists and is a valid UUID - And the response body property "$[0].qosProfile" has the value provided for createBooking - And the response body property "$[0].startTime" has the value provided for createBooking - And the response body property "$[0].duration" has the value provided for createBooking - And the response body property "$[0].serviceArea" has the value provided for createBooking - - # Error scenarios for POST /qos-bookings - @qos_bookings_createBooking_400_num_devices_out_of_range - Scenario: Create booking fails when numDevices exceeds maximum of 50 - Given the resource "/qos-booking-and-assignment/vwip/qos-bookings" - And the header "Content-Type" is set to "application/json" - And the operationId is "createBooking" - And the request body is set to a request body compliant with the schema at "/components/schemas/BookingInput" - And the request body property "$.numDevices" is set to 51 - And the request body property "$.qosProfile" is set to a valid QoS Profile as returned by QoS Profiles API - And the request body property "$.startTime" is set to a valid time - And the request body property "$.duration" is set to a valid duration for the selected QoS profile - And the request body property "$.serviceArea" is set to a valid service area compliant with schema at "/components/schemas/Area" - When the request "createBooking" is sent - Then the response status code is 400 - And the response header "Content-Type" is "application/json" - And the response body property "$.status" is 400 - And the response body property "$.code" is "OUT_OF_RANGE" - - @qos_bookings_createBooking_400_duration_out_of_range - Scenario: Create booking fails when duration exceeds maximum of 86400 seconds - Given the resource "/qos-booking-and-assignment/vwip/qos-bookings" - And the header "Content-Type" is set to "application/json" - And the operationId is "createBooking" - And the request body is set to a request body compliant with the schema at "/components/schemas/BookingInput" - And the request body property "$.qosProfile" is set to a valid QoS Profile as returned by QoS Profiles API - And the request body property "$.startTime" is set to a valid time - And the request body property "$.duration" is set to 86401 - And the request body property "$.serviceArea" is set to a valid service area compliant with schema at "/components/schemas/Area" - When the request "createBooking" is sent - Then the response status code is 400 - And the response header "Content-Type" is "application/json" - And the response body property "$.status" is 400 - And the response body property "$.code" is "QOS_BOOKING_AND_ASSIGNMENT.DURATION_OUT_OF_RANGE" - - @qos_bookings_createBooking_400_unknown_property - Scenario: Create booking fails when request body contains a property not declared in the schema - Given the resource "/qos-booking-and-assignment/vwip/qos-bookings" - And the header "Content-Type" is set to "application/json" - And the operationId is "createBooking" - And the request body is set to a request body compliant with the schema at "/components/schemas/BookingInput" - And the request body property "$.qosProfile" is set to a valid QoS Profile as returned by QoS Profiles API - And the request body property "$.startTime" is set to a valid time - And the request body property "$.duration" is set to a valid duration for the selected QoS profile - And the request body property "$.serviceArea" is set to a valid service area compliant with schema at "/components/schemas/Area" - And the request body includes an undeclared property "$.unexpectedParam" set to any value - When the request "createBooking" is sent - Then the response status code is 400 - And the response header "Content-Type" is "application/json" - And the response body property "$.status" is 400 - And the response body property "$.code" is "INVALID_ARGUMENT" - - @qos_bookings_createBooking_409_incompatible_state - Scenario: Create booking fails when an incompatible booking already exists for the same device and overlapping schedule - Given the resource "/qos-booking-and-assignment/vwip/qos-bookings" - And the header "Content-Type" is set to "application/json" - And the operationId is "createBooking" - And an existing QoS booking already exists for the same device with an overlapping time slot and service area - And the request body is set to a request body compliant with the schema at "/components/schemas/BookingInput" - And the request body property "$.qosProfile" is set to a valid QoS Profile as returned by QoS Profiles API - And the request body property "$.startTime" is set to a time overlapping with the existing booking - And the request body property "$.duration" is set to a valid duration for the selected QoS profile - And the request body property "$.serviceArea" is set to a service area overlapping with the existing booking - When the request "createBooking" is sent - Then the response status code is 409 - And the response header "Content-Type" is "application/json" - And the response body property "$.status" is 409 - And the response body property "$.code" is "INCOMPATIBLE_STATE" - - # Error scenarios for POST /qos-bookings/{bookingId}/devices/assign - @devices_assignDevices_400_too_many_devices - Scenario: Assign devices fails when the devices array exceeds the maximum of 50 - Given the resource "/qos-booking-and-assignment/vwip/qos-bookings/{bookingId}/devices/assign" - And the "bookingId" is created by operation "createBooking" - And the operationId is "assignDevices" - And the request body property "$.devices" is set to an array of 51 valid device identifiers compliant with schema at "/components/schemas/Device" - When the request "assignDevices" is sent - Then the response status code is 400 - And the response header "Content-Type" is "application/json" - And the response body property "$.status" is 400 - And the response body property "$.code" is "INVALID_ARGUMENT" - - @devices_assignDevices_400_unknown_property - Scenario: Assign devices fails when request body contains a property not declared in the schema - Given the resource "/qos-booking-and-assignment/vwip/qos-bookings/{bookingId}/devices/assign" - And the "bookingId" is created by operation "createBooking" - And the operationId is "assignDevices" - And the request body complies with the OAS schema at "/components/schemas/DeviceAssignmentInput" - And the request body property "$.devices" is set to a valid array of device identifiers compliant with schema at "/components/schemas/Devices" - And the request body includes an undeclared property "$.unexpectedParam" set to any value - When the request "assignDevices" is sent - Then the response status code is 400 - And the response header "Content-Type" is "application/json" - And the response body property "$.status" is 400 - And the response body property "$.code" is "INVALID_ARGUMENT" - - # Error scenarios for POST /qos-bookings/retrieve - @devices_retrieveBooking_400_unknown_property - Scenario: Retrieve booking fails when request body contains a property not declared in the schema - Given the resource "/qos-booking-and-assignment/vwip/qos-bookings/retrieve" - And the operationId is "retrieveBookingByDevice" - And the request body complies with the OAS schema at "/components/schemas/RetrieveBookingByDevice" - And the request body includes an undeclared property "$.unexpectedParam" set to any value - When the request "retrieveBookingByDevice" is sent - Then the response status code is 400 - And the response header "Content-Type" is "application/json" - And the response body property "$.status" is 400 - And the response body property "$.code" is "INVALID_ARGUMENT"