Skip to content

Commit bd141eb

Browse files
authored
Merge pull request #7734 from nextcloud/feat/federation-integration-tests
test: add federation tests to CI
2 parents ebc6c9d + 71afff4 commit bd141eb

12 files changed

Lines changed: 712 additions & 9 deletions

File tree

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
name: Federation integration tests
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- '.github/workflows/integration-federation.yml'
7+
- 'appinfo/**'
8+
- 'lib/**'
9+
- 'templates/**'
10+
- 'tests/**'
11+
- 'composer.json'
12+
- 'composer.lock'
13+
push:
14+
branches:
15+
- main
16+
- master
17+
- stable*
18+
19+
permissions:
20+
contents: read
21+
22+
env:
23+
APP_NAME: deck
24+
25+
jobs:
26+
federation:
27+
runs-on: ubuntu-latest
28+
29+
strategy:
30+
fail-fast: false
31+
matrix:
32+
php-versions: ['8.2']
33+
server-versions: ['master']
34+
35+
name: php${{ matrix.php-versions }}-${{ matrix.server-versions }}
36+
37+
steps:
38+
- name: Checkout server
39+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
40+
with:
41+
persist-credentials: false
42+
repository: nextcloud/server
43+
ref: ${{ matrix.server-versions }}
44+
submodules: true
45+
46+
- name: Checkout app
47+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
48+
with:
49+
persist-credentials: false
50+
path: apps/${{ env.APP_NAME }}
51+
52+
- name: Checkout activity
53+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
54+
with:
55+
persist-credentials: false
56+
repository: nextcloud/activity
57+
ref: ${{ matrix.server-versions }}
58+
path: apps/activity
59+
60+
- name: Set up php ${{ matrix.php-versions }}
61+
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # v2.36.0
62+
with:
63+
php-version: ${{ matrix.php-versions }}
64+
extensions: mbstring, iconv, fileinfo, intl, sqlite, pdo_sqlite, apcu, gd
65+
ini-values:
66+
apc.enable_cli=on
67+
coverage: none
68+
69+
- name: Set up dependencies
70+
working-directory: apps/${{ env.APP_NAME }}
71+
run: composer i --no-dev
72+
73+
- name: Set up Nextcloud
74+
run: |
75+
mkdir data
76+
./occ maintenance:install --verbose --database=sqlite --database-name=nextcloud --admin-user admin --admin-pass admin
77+
./occ config:system:set hashing_default_password --value=true --type=boolean
78+
./occ config:system:set memcache.local --value="\\OC\\Memcache\\APCu"
79+
./occ config:system:set memcache.distributed --value="\\OC\\Memcache\\APCu"
80+
cat config/config.php
81+
./occ app:enable --force ${{ env.APP_NAME }}
82+
83+
- name: Run federation behat tests
84+
working-directory: apps/${{ env.APP_NAME }}/tests/integration
85+
run: ./run-federation.sh
86+
87+
- name: Print log
88+
if: always()
89+
run: |
90+
if [ -f data/nextcloud.log ]; then
91+
cat data/nextcloud.log
92+
else
93+
echo "Log file not found"
94+
fi

lib/Db/BoardMapper.php

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ public function findAllByUser(string $userId, ?int $limit = null, ?int $offset =
190190
// FIXME this used to be a UNION to get boards owned by $userId and the user shares in one single query
191191
// Is it possible with the query builder?
192192
$qb = $this->db->getQueryBuilder();
193-
$qb->select('id', 'title', 'owner', 'color', 'archived', 'deleted_at', 'last_modified')
193+
$qb->select('id', 'title', 'owner', 'color', 'archived', 'deleted_at', 'last_modified', 'external_id', 'share_token')
194194
// this does not work in MySQL/PostgreSQL
195195
//->selectAlias('0', 'shared')
196196
->from('deck_boards', 'b')
@@ -230,7 +230,7 @@ public function findAllByUser(string $userId, ?int $limit = null, ?int $offset =
230230

231231
// shared with user
232232
$qb = $this->db->getQueryBuilder();
233-
$qb->select('b.id', 'title', 'owner', 'color', 'archived', 'deleted_at', 'last_modified')
233+
$qb->select('b.id', 'title', 'owner', 'color', 'archived', 'deleted_at', 'last_modified', 'external_id', 'share_token')
234234
//->selectAlias('1', 'shared')
235235
->from('deck_boards', 'b')
236236
->innerJoin('b', 'deck_board_acl', 'acl', $qb->expr()->eq('b.id', 'acl.board_id'))
@@ -298,7 +298,7 @@ public function findAllByGroups(string $userId, array $groups, ?int $limit = nul
298298
return [];
299299
}
300300
$qb = $this->db->getQueryBuilder();
301-
$qb->select('b.id', 'title', 'owner', 'color', 'archived', 'deleted_at', 'last_modified')
301+
$qb->select('b.id', 'title', 'owner', 'color', 'archived', 'deleted_at', 'last_modified', 'external_id', 'share_token')
302302
//->selectAlias('2', 'shared')
303303
->from('deck_boards', 'b')
304304
->innerJoin('b', 'deck_board_acl', 'acl', $qb->expr()->eq('b.id', 'acl.board_id'))
@@ -354,7 +354,7 @@ public function findAllByCircles(string $userId, ?int $limit = null, ?int $offse
354354
}
355355

356356
$qb = $this->db->getQueryBuilder();
357-
$qb->select('b.id', 'title', 'owner', 'color', 'archived', 'deleted_at', 'last_modified')
357+
$qb->select('b.id', 'title', 'owner', 'color', 'archived', 'deleted_at', 'last_modified', 'external_id', 'share_token')
358358
//->selectAlias('2', 'shared')
359359
->from('deck_boards', 'b')
360360
->innerJoin('b', 'deck_board_acl', 'acl', $qb->expr()->eq('b.id', 'acl.board_id'))
@@ -404,7 +404,7 @@ public function findAllByCircles(string $userId, ?int $limit = null, ?int $offse
404404

405405
public function findAllByTeam(string $teamId): array {
406406
$qb = $this->db->getQueryBuilder();
407-
$qb->select('b.id', 'title', 'owner', 'color', 'archived', 'deleted_at', 'last_modified')
407+
$qb->select('b.id', 'title', 'owner', 'color', 'archived', 'deleted_at', 'last_modified', 'external_id', 'share_token')
408408
->from('deck_boards', 'b')
409409
->innerJoin('b', 'deck_board_acl', 'acl', $qb->expr()->eq('b.id', 'acl.board_id'))
410410
->where($qb->expr()->eq('acl.type', $qb->createNamedParameter(Acl::PERMISSION_TYPE_CIRCLE, IQueryBuilder::PARAM_INT)))
@@ -432,7 +432,7 @@ public function findTeamsForBoard(int $boardId): array {
432432

433433
public function isSharedWithTeam(int $boardId, string $teamId): bool {
434434
$qb = $this->db->getQueryBuilder();
435-
$qb->select('b.id', 'title', 'owner', 'color', 'archived', 'deleted_at', 'last_modified')
435+
$qb->select('b.id', 'title', 'owner', 'color', 'archived', 'deleted_at', 'last_modified', 'external_id', 'share_token')
436436
->from('deck_boards', 'b')
437437
->innerJoin('b', 'deck_board_acl', 'acl', $qb->expr()->eq('b.id', 'acl.board_id'))
438438
->where($qb->expr()->eq('b.id', $qb->createNamedParameter($boardId, IQueryBuilder::PARAM_INT)))
@@ -458,7 +458,7 @@ public function findToDelete() {
458458
// add buffer of 5 min
459459
$timeLimit = time() - (60 * 5);
460460
$qb = $this->db->getQueryBuilder();
461-
$qb->select('id', 'title', 'owner', 'color', 'archived', 'deleted_at', 'last_modified')
461+
$qb->select('id', 'title', 'owner', 'color', 'archived', 'deleted_at', 'last_modified', 'external_id', 'share_token')
462462
->from('deck_boards')
463463
->where($qb->expr()->gt('deleted_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT)))
464464
->andWhere($qb->expr()->lt('deleted_at', $qb->createNamedParameter($timeLimit, IQueryBuilder::PARAM_INT)));

lib/Db/Stack.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
* @method \int getOrder()
2323
* @method void setOrder(int $order)
2424
* @method Card[] getCards()
25+
* @method bool getIsDoneColumn()
26+
* @method void setIsDoneColumn(bool $isDoneColumn)
2527
*/
2628
class Stack extends RelationalEntity {
2729
protected $title;

lib/Service/BoardService.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,18 @@ public function addAcl(int $boardId, int $type, $participant, bool $edit, bool $
420420

421421
$this->eventDispatcher->dispatchTyped(new AclCreatedEvent($acl));
422422

423+
// Sync permissions to remote server since shareReceived() creates ACL with no permissions
424+
if ($type === Acl::PERMISSION_TYPE_REMOTE && ($edit || $share || $manage)) {
425+
$notification = $this->federationFactory->getCloudFederationNotification();
426+
$payload = [
427+
$newAcl->jsonSerialize(),
428+
'sharedSecret' => $newAcl->getToken(),
429+
];
430+
$notification->setMessage('update-permissions', 'deck', (string)$boardId, $payload);
431+
$url = $this->cloudIdManager->resolveCloudId($participant);
432+
$this->cloudFederationProviderManager->sendCloudNotification($url->getRemote(), $notification);
433+
}
434+
423435
return $newAcl;
424436
}
425437

lib/Service/ExternalBoardService.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ public function createStackOnRemote(
165165
int $order = 0,
166166
): array {
167167
$this->configService->ensureFederationEnabled();
168-
$this->permissionService->checkPermission($this->boardMapper, $localBoard->getId(), Acl::PERMISSION_EDIT, $this->userId, false, false);
168+
$this->permissionService->checkPermission($this->boardMapper, $localBoard->getId(), Acl::PERMISSION_MANAGE, $this->userId, false, false);
169169
$shareToken = $localBoard->getShareToken();
170170
$participantCloudId = $this->cloudIdManager->getCloudId($this->userId, null);
171171
$ownerCloudId = $this->cloudIdManager->resolveCloudId($localBoard->getOwner());

tests/integration/config/behat.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ default:
77
test:
88
paths:
99
- '%paths.base%/../features/'
10+
filters:
11+
tags: '~@federation'
1012
contexts:
1113
- ServerContext:
1214
baseUrl: http://localhost:8080/
@@ -16,3 +18,8 @@ default:
1618
- AttachmentContext
1719
- SearchContext
1820
- SessionContext
21+
federation:
22+
paths:
23+
- '%paths.base%/../features/federation/'
24+
contexts:
25+
- FederationContext

0 commit comments

Comments
 (0)