Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion tests/integration/base-query-count.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
96706
198420
1 change: 1 addition & 0 deletions tests/integration/config/behat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ default:
baseUrl: http://localhost:8080/
- RequestContext
- BoardContext
- DeckApiContext
- CommentContext
- AttachmentContext
- SearchContext
Expand Down
94 changes: 94 additions & 0 deletions tests/integration/features/api/attachments.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
Feature: REST API - Attachments
Basic coverage of the attachment endpoints documented at
https://deck.readthedocs.io/en/stable/API/#attachments

Background:
Given user "admin" exists
And user "user0" exists
And user "user1" exists
And acting as user "user0"
And sending "POST" to the API endpoint "/boards" with body:
| title | Attachment board |
| color | ff0000 |
And the response value "id" is stored as "boardId"
And sending "POST" to the API endpoint "/boards/<boardId>/stacks" with body:
| title | ToDo |
| order | 1 |
And the response value "id" is stored as "stackId"
And sending "POST" to the API endpoint "/boards/<boardId>/stacks/<stackId>/cards" with body:
| title | Card with attachments |
| type | plain |
| order | 999 |
And the response value "id" is stored as "cardId"

Scenario: POST /boards/{boardId}/stacks/{stackId}/cards/{cardId}/attachments - Upload an attachment
When uploading the file "test.txt" with content "Example content" as attachment type "deck_file" to the API endpoint "/boards/<boardId>/stacks/<stackId>/cards/<cardId>/attachments"
Then the response should have a status code "200"
And the response value "cardId" should be "<cardId>"
And the response value "type" should be "deck_file"
And the response value "data" should be "test.txt"
And the response value "createdBy" should be "user0"
And the response value "deletedAt" should be "0"
And the response value "extendedData.filesize" should be "15"

Scenario: GET /boards/{boardId}/stacks/{stackId}/cards/{cardId}/attachments - Get a list of attachments
Given uploading the file "test.txt" with content "Example content" as attachment type "deck_file" to the API endpoint "/boards/<boardId>/stacks/<stackId>/cards/<cardId>/attachments"
And the response should have a status code "200"
When sending "GET" to the API endpoint "/boards/<boardId>/stacks/<stackId>/cards/<cardId>/attachments"
Then the response should have a status code "200"
And the response should be a list of objects
And the response list should contain 1 entry
And the response list should contain an entry with "data" set to "test.txt"
And the response value "0.extendedData.info.filename" should be "test"
And the response value "0.extendedData.info.extension" should be "txt"

Scenario: GET /boards/{boardId}/stacks/{stackId}/cards/{cardId}/attachments/{attachmentId} - Get the attachment file
Given uploading the file "test.txt" with content "Example content" as attachment type "deck_file" to the API endpoint "/boards/<boardId>/stacks/<stackId>/cards/<cardId>/attachments"
And the response value "id" is stored as "attachmentId"
When sending "GET" to the API endpoint "/boards/<boardId>/stacks/<stackId>/cards/<cardId>/attachments/<attachmentId>"
Then the response should have a status code "200"
And the response body should be "Example content"

Scenario: DELETE /boards/{boardId}/stacks/{stackId}/cards/{cardId}/attachments/{attachmentId} - Delete and restore an attachment
Given uploading the file "test.txt" with content "Example content" as attachment type "deck_file" to the API endpoint "/boards/<boardId>/stacks/<stackId>/cards/<cardId>/attachments"
And the response value "id" is stored as "attachmentId"
When sending "DELETE" to the API endpoint "/boards/<boardId>/stacks/<stackId>/cards/<cardId>/attachments/<attachmentId>"
Then the response should have a status code "200"
And the response value "deletedAt" should not be "0"
# Attachments are deleted in two steps, so they stay listed with a deletion
# timestamp until they are either restored or removed for good
When sending "GET" to the API endpoint "/boards/<boardId>/stacks/<stackId>/cards/<cardId>/attachments"
Then the response list should contain 1 entry
And the response value "0.deletedAt" should not be "0"
When sending "PUT" to the API endpoint "/boards/<boardId>/stacks/<stackId>/cards/<cardId>/attachments/<attachmentId>/restore"
Then the response should have a status code "200"
And the response value "deletedAt" should be "0"
When sending "GET" to the API endpoint "/boards/<boardId>/stacks/<stackId>/cards/<cardId>/attachments"
Then the response list should contain 1 entry
And the response value "0.deletedAt" should be "0"

Scenario: Attachments stored in the files app are only returned by API version 1.1
Given using the Deck API version "1.1"
When uploading the file "in-files.txt" with content "Example content" as attachment type "file" to the API endpoint "/boards/<boardId>/stacks/<stackId>/cards/<cardId>/attachments"
Then the response should have a status code "200"
And the response value "type" should be "file"
When sending "GET" to the API endpoint "/boards/<boardId>/stacks/<stackId>/cards/<cardId>/attachments"
Then the response should have a status code "200"
And the response list should contain 1 entry
And the response list should contain an entry with "type" set to "file"
# API version 1.0 predates the files app integration and only knows deck_file attachments
Given using the Deck API version "1.0"
When sending "GET" to the API endpoint "/boards/<boardId>/stacks/<stackId>/cards/<cardId>/attachments"
Then the response should have a status code "200"
And the response list should contain 0 entries

Scenario: Attachments of a board of another user are not accessible
Given uploading the file "test.txt" with content "Example content" as attachment type "deck_file" to the API endpoint "/boards/<boardId>/stacks/<stackId>/cards/<cardId>/attachments"
And the response value "id" is stored as "attachmentId"
And acting as user "user1"
When sending "GET" to the API endpoint "/boards/<boardId>/stacks/<stackId>/cards/<cardId>/attachments"
Then the response should have a status code "403"
When sending "GET" to the API endpoint "/boards/<boardId>/stacks/<stackId>/cards/<cardId>/attachments/<attachmentId>"
Then the response should have a status code "403"
When sending "DELETE" to the API endpoint "/boards/<boardId>/stacks/<stackId>/cards/<cardId>/attachments/<attachmentId>"
Then the response should have a status code "403"
47 changes: 47 additions & 0 deletions tests/integration/features/api/authentication.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
Feature: REST API - Authentication
The API is meant to be consumed by external integrations rather than by a
browser, so it has to stay reachable with basic auth and without a CSRF
token, see https://deck.readthedocs.io/en/stable/API/#prerequisites

Background:
Given user "admin" exists
And user "user0" exists
And user "user1" exists
And acting as user "user0"
And sending "POST" to the API endpoint "/boards" with body:
| title | Integration board |
| color | ff0000 |
And the response value "id" is stored as "boardId"

Scenario: Unauthenticated requests are rejected
When sending "GET" to the API endpoint "/boards" without authentication
Then the response should have a status code "401"
When sending "GET" to the API endpoint "/boards/<boardId>" without authentication
Then the response should have a status code "401"

# The password is the one the shared behat provisioning steps assign to new users
Scenario: A client can use the API with basic auth and without a CSRF token
When sending "GET" to the API endpoint "/boards" as "user0" with password "123456"
Then the response should have a status code "200"
And the response list should contain an entry with "title" set to "Integration board"
When sending "GET" to the API endpoint "/boards/<boardId>" as "user0" with password "123456"
Then the response should have a status code "200"
And the response value "title" should be "Integration board"

Scenario: Basic auth is bound to the authenticated user
When sending "GET" to the API endpoint "/boards/<boardId>" as "user1" with password "123456"
Then the response should have a status code "403"
And the response value "message" should be "Permission denied"
When sending "GET" to the API endpoint "/boards" as "user1" with password "123456"
Then the response should have a status code "200"
And the response list should not contain an entry with "title" set to "Integration board"

Scenario: A client can write through the API with basic auth
When sending "POST" to the API endpoint "/boards/<boardId>/stacks" as "user0" with password "123456" and body:
| title | Stack from a client |
| order | 1 |
Then the response should have a status code "200"
And the response value "title" should be "Stack from a client"
When sending "GET" to the API endpoint "/boards/<boardId>/stacks"
Then the response should have a status code "200"
And the response list should contain an entry with "title" set to "Stack from a client"
208 changes: 208 additions & 0 deletions tests/integration/features/api/boards.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
Feature: REST API - Boards
Basic coverage of the board endpoints documented at
https://deck.readthedocs.io/en/stable/API/#boards

Background:
Given user "admin" exists
And user "user0" exists
And user "user1" exists
And acting as user "user0"

Scenario: POST /boards - Create a new board
When sending "POST" to the API endpoint "/boards" with body:
| title | Board title |
| color | ff0000 |
Then the response should have a status code "200"
And the response value "title" should be "Board title"
And the response value "color" should be "ff0000"
And the response value "archived" should be "false"
And the response value "deletedAt" should be "0"
And the response value "owner.uid" should be "user0"
And the response value "permissions.PERMISSION_READ" should be "true"
And the response value "permissions.PERMISSION_EDIT" should be "true"
And the response value "permissions.PERMISSION_MANAGE" should be "true"
And the response value "permissions.PERMISSION_SHARE" should be "true"
And the response value "acl" should be empty
And the response value "labels" should have 4 entries

Scenario: POST /boards - Fail to create a board with invalid parameters
When sending "POST" to the API endpoint "/boards" with body:
| title | This is a very long name that exceeds the maximum length of a deck board which is limited to 100 characters |
| color | ff0000 |
Then the response should have a status code "400"
And the response value "status" should be "400"
When sending "POST" to the API endpoint "/boards" with body:
| title | Board title |
| color | |
Then the response should have a status code "400"
And the response value "status" should be "400"

Scenario: GET /boards - Get a list of boards
Given sending "POST" to the API endpoint "/boards" with body:
| title | Listed board |
| color | 00ff00 |
And the response should have a status code "200"
When sending "GET" to the API endpoint "/boards"
Then the response should have a status code "200"
And the response should be a list of objects
And the response list should contain an entry with "title" set to "Listed board"
And the response should have the header "ETag"

Scenario: GET /boards - Get a list of boards with details
Given sending "POST" to the API endpoint "/boards" with body:
| title | Detailed board |
| color | 00ff00 |
And the response value "id" is stored as "boardId"
When sending "GET" to the API endpoint "/boards?details=true"
Then the response should have a status code "200"
And the response list should contain an entry with "id" set to "<boardId>"

Scenario: GET /boards - Limit the board list with If-Modified-Since
Given sending "POST" to the API endpoint "/boards" with body:
| title | Unmodified board |
| color | 00ff00 |
When sending "GET" to the API endpoint "/boards" with the header "If-Modified-Since" set to "Sun, 03 Aug 2036 10:34:12 GMT"
Then the response should have a status code "200"
And the response list should contain 0 entries

Scenario: GET /boards/{boardId} - Get board details
Given sending "POST" to the API endpoint "/boards" with body:
| title | Board details |
| color | 0000ff |
And the response value "id" is stored as "boardId"
When sending "GET" to the API endpoint "/boards/<boardId>"
Then the response should have a status code "200"
And the response value "id" should be "<boardId>"
And the response value "title" should be "Board details"
And the response value "color" should be "0000ff"
And the response should have the header "ETag"

Scenario: GET /boards/{boardId} - Unchanged boards are answered with 304 Not Modified
Given sending "POST" to the API endpoint "/boards" with body:
| title | Etag board |
| color | 0000ff |
And the response value "id" is stored as "boardId"
And sending "GET" to the API endpoint "/boards/<boardId>"
And the response header "ETag" is stored as "boardEtag"
When sending "GET" to the API endpoint "/boards/<boardId>" with the header "If-None-Match" set to "<boardEtag>"
Then the response should have a status code "304"

Scenario: PUT /boards/{boardId} - Update board details
Given sending "POST" to the API endpoint "/boards" with body:
| title | Board to update |
| color | ff0000 |
And the response value "id" is stored as "boardId"
When sending "PUT" to the API endpoint "/boards/<boardId>" with body:
| title | Updated board |
| color | 00ff00 |
| archived | true |
Then the response should have a status code "200"
And the response value "title" should be "Updated board"
And the response value "color" should be "00ff00"
And the response value "archived" should be "true"
When sending "GET" to the API endpoint "/boards/<boardId>"
Then the response value "title" should be "Updated board"
And the response value "archived" should be "true"

Scenario: DELETE /boards/{boardId} - Delete a board and restore it again
Given sending "POST" to the API endpoint "/boards" with body:
| title | Board to delete |
| color | ff0000 |
And the response value "id" is stored as "boardId"
When sending "DELETE" to the API endpoint "/boards/<boardId>"
Then the response should have a status code "200"
# Boards are deleted in two steps, so they stay listed with a deletion timestamp
# until they are either restored or removed for good by the cleanup job
And the response value "deletedAt" should not be "0"
When sending "POST" to the API endpoint "/boards/<boardId>/undo_delete"
Then the response should have a status code "200"
And the response value "deletedAt" should be "0"
When sending "GET" to the API endpoint "/boards/<boardId>"
Then the response should have a status code "200"
And the response value "title" should be "Board to delete"
And the response value "deletedAt" should be "0"

Scenario: POST /boards/{boardId}/acl - Add, update and delete an acl rule
Given sending "POST" to the API endpoint "/boards" with body:
| title | Shared board |
| color | ff0000 |
And the response value "id" is stored as "boardId"
When sending "POST" to the API endpoint "/boards/<boardId>/acl" with body:
| type | 0 |
| participant | user1 |
| permissionEdit | true |
| permissionShare | false |
| permissionManage | false |
Then the response should have a status code "200"
And the response value "participant.uid" should be "user1"
And the response value "type" should be "0"
And the response value "boardId" should be "<boardId>"
And the response value "permissionEdit" should be "true"
And the response value "permissionShare" should be "false"
And the response value "permissionManage" should be "false"
And the response value "owner" should be "false"
And the response value "id" is stored as "aclId"

When sending "PUT" to the API endpoint "/boards/<boardId>/acl/<aclId>" with body:
| permissionEdit | false |
| permissionShare | true |
| permissionManage | true |
Then the response should have a status code "200"
And the response value "permissionEdit" should be "false"
And the response value "permissionShare" should be "true"
And the response value "permissionManage" should be "true"

Given acting as user "user1"
When sending "GET" to the API endpoint "/boards"
Then the response list should contain an entry with "title" set to "Shared board"

Given acting as user "user0"
When sending "DELETE" to the API endpoint "/boards/<boardId>/acl/<aclId>"
Then the response should have a status code "200"
Given acting as user "user1"
When sending "GET" to the API endpoint "/boards"
Then the response list should not contain an entry with "title" set to "Shared board"

Scenario: POST /boards/{boardId}/clone - Clone a board
Given sending "POST" to the API endpoint "/boards" with body:
| title | Board to clone |
| color | ff0000 |
And the response value "id" is stored as "boardId"
And sending "POST" to the API endpoint "/boards/<boardId>/stacks" with body:
| title | ToDo |
| order | 1 |
And the response value "id" is stored as "stackId"
And sending "POST" to the API endpoint "/boards/<boardId>/stacks/<stackId>/cards" with body:
| title | Card to clone |
| type | plain |
| order | 999 |
When sending "POST" to the API endpoint "/boards/<boardId>/clone" with body:
| withCards | true |
Then the response should have a status code "200"
And the response value "title" should be "Board to clone (copy)"
And the response value "id" should not be "<boardId>"
And the response value "id" is stored as "clonedBoardId"
When sending "GET" to the API endpoint "/boards/<clonedBoardId>/stacks"
Then the response should have a status code "200"
And the response list should contain 1 entry
And the response value "0.title" should be "ToDo"
And the response value "0.cards" should have 1 entry
And the response value "0.cards.0.title" should be "Card to clone"

Scenario: Boards of other users are not accessible
Given sending "POST" to the API endpoint "/boards" with body:
| title | Private board |
| color | ff0000 |
And the response value "id" is stored as "boardId"
Given acting as user "user1"
When sending "GET" to the API endpoint "/boards/<boardId>"
Then the response should have a status code "403"
And the response value "status" should be "403"
And the response value "message" should be "Permission denied"
When sending "PUT" to the API endpoint "/boards/<boardId>" with body:
| title | Hijacked board |
| color | 00ff00 |
| archived | false |
Then the response should have a status code "403"
When sending "DELETE" to the API endpoint "/boards/<boardId>"
Then the response should have a status code "403"
Loading
Loading