Skip to content
Merged
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
18 changes: 18 additions & 0 deletions .github/workflows/api-performance-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: "Tests: API performance test"

on:
workflow_dispatch:
pull_request:
types: [ opened, labeled, unlabeled, synchronize ]
schedule:
- cron: '51 4 * * *'

concurrency:
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref_name }}
cancel-in-progress: false

jobs:
api-performance-test:
name: 'API performance test'
if: contains(github.event.pull_request.labels.*.name, 'api-performance-test!') || github.event_name != 'pull_request'
uses: ./.github/workflows/reusable-api-performance-test.yml
68 changes: 68 additions & 0 deletions .github/workflows/reusable-api-performance-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
name: '[reusable only] api performance tests'

on:
workflow_call:

jobs:
api-performance-test:
name: 'Tests: API performance tests'
runs-on: ubuntu-latest
env:
TEST_DATABASE_URL: postgresql://ecamp3:ecamp3@localhost:5432/ecamp3test?serverVersion=15&charset=utf8

services:
postgres:
image: 'postgres:15-alpine'
env:
POSTGRES_DB: 'ecamp3test'
POSTGRES_PASSWORD: 'ecamp3'
POSTGRES_USER: 'ecamp3'
ports:
- '5432:5432'
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5

steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4

- uses: shivammathur/setup-php@v2
with:
php-version: '8.3.2'
extensions: intl-73.1
tools: composer:2.7.0
coverage: pcov

- name: Get Composer Cache Directory
id: composer-cache
run: 'echo "dir=$(composer config cache-files-dir)" | tr -d "\n" >> $GITHUB_OUTPUT'
working-directory: api

- uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-composer-

- run: composer install --prefer-dist --no-progress --no-interaction
working-directory: api

- run: |
mkdir -p var/cache var/log
jwt_passphrase=${JWT_PASSPHRASE:-$(grep ''^JWT_PASSPHRASE='' .env | cut -f 2 -d ''='')}
echo "Generating public / private keys for JWT"
mkdir -p config/jwt
echo "$jwt_passphrase" | openssl genpkey -out config/jwt/private.pem -pass stdin -aes256 -algorithm rsa -pkeyopt rsa_keygen_bits:4096
echo "$jwt_passphrase" | openssl pkey -in config/jwt/private.pem -passin stdin -out config/jwt/public.pem -pubout
setfacl -R -m u:www-data:rX -m u:"$(whoami)":rwX config/jwt
setfacl -dR -m u:www-data:rX -m u:"$(whoami)":rwX config/jwt
working-directory: api

- run: php bin/console doctrine:migrations:migrate --no-interaction -e test
working-directory: api

- run: composer performance_test
working-directory: api
9 changes: 9 additions & 0 deletions api/.env.performance_test
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# define your env variables for the test env here
KERNEL_CLASS='App\Kernel'
APP_SECRET='$ecretf0rt3st'
SYMFONY_DEPRECATIONS_HELPER=999999
PANTHER_APP_ENV=panther
PANTHER_ERROR_SCREENSHOT_DIR=./var/error-screenshots
ADDITIONAL_TRUSTED_HOSTS=example.com
COOKIE_PREFIX=example_com_
TRANSLATE_ERRORS_TO_LOCALES="en,en_CH_scout,de,de_CH_scout,fr,fr_CH_scout,it,it_CH_scout,rm,rm_CH_scout"
8 changes: 8 additions & 0 deletions api/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,14 @@
"bin/phpunit -d memory_limit=-1 -d --update-snapshots tests/Api/SnapshotTests",
"bin/phpunit -d memory_limit=-1 -d --update-snapshots tests/Util/ArrayDeepSortTest.php"
],
"performance_test": [
"Composer\\Config::disableProcessTimeout",
"bin/phpunit -d memory_limit=-1 -c phpunit.performance_test.xml.dist"
],
"performance_test_update-snapshots": [
"Composer\\Config::disableProcessTimeout",
"bin/phpunit -d memory_limit=-1 -d --update-snapshots -c phpunit.performance_test.xml.dist"
],
"auto-scripts": {
"cache:clear": "symfony-cmd",
"assets:install %PUBLIC_DIR%": "symfony-cmd"
Expand Down
10 changes: 5 additions & 5 deletions api/config/bundles.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,16 @@
DoctrineBundle::class => ['all' => true],
ApiPlatformBundle::class => ['all' => true],
NelmioCorsBundle::class => ['all' => true],
WebProfilerBundle::class => ['dev' => true, 'test' => true],
WebProfilerBundle::class => ['dev' => true, 'test' => true, 'performance_test' => true],
MakerBundle::class => ['dev' => true],
DoctrineMigrationsBundle::class => ['all' => true],
MonologBundle::class => ['all' => true],
DebugBundle::class => ['dev' => true, 'test' => true],
DebugBundle::class => ['dev' => true, 'test' => true, 'performance_test' => true],
StofDoctrineExtensionsBundle::class => ['all' => true],
LexikJWTAuthenticationBundle::class => ['all' => true],
NelmioAliceBundle::class => ['dev' => true, 'test' => true],
FidryAliceDataFixturesBundle::class => ['dev' => true, 'test' => true],
HautelookAliceBundle::class => ['dev' => true, 'test' => true],
NelmioAliceBundle::class => ['dev' => true, 'test' => true, 'performance_test' => true],
FidryAliceDataFixturesBundle::class => ['dev' => true, 'test' => true, 'performance_test' => true],
HautelookAliceBundle::class => ['dev' => true, 'test' => true, 'performance_test' => true],
ExerciseHTMLPurifierBundle::class => ['all' => true],
KnpUOAuth2ClientBundle::class => ['all' => true],
SentryBundle::class => ['all' => true],
Expand Down
6 changes: 5 additions & 1 deletion api/config/packages/framework.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,8 @@ framework:

when@test:
framework:
test: true
test: true

when@performance_test:
framework:
test: true
2 changes: 2 additions & 0 deletions api/config/packages/performance_test/doctrine.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
imports:
- resource: ../test/doctrine.yaml
2 changes: 2 additions & 0 deletions api/config/packages/performance_test/doctrine_migrations.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
imports:
- resource: ../test/doctrine.yaml
2 changes: 2 additions & 0 deletions api/config/packages/performance_test/hautelook_alice.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
imports:
- resource: ../test/hautelook_alice.yaml
2 changes: 2 additions & 0 deletions api/config/packages/performance_test/mailer.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
imports:
- resource: ../test/mailer.yaml
2 changes: 2 additions & 0 deletions api/config/packages/performance_test/monolog.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
imports:
- resource: ../test/monolog.yaml
2 changes: 2 additions & 0 deletions api/config/packages/performance_test/nelmio_alice.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
imports:
- resource: ../test/nelmio_alice.yaml
2 changes: 2 additions & 0 deletions api/config/packages/performance_test/routing.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
imports:
- resource: ../test/routing.yaml
2 changes: 2 additions & 0 deletions api/config/packages/performance_test/validator.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
imports:
- resource: ../test/validator.yaml
2 changes: 2 additions & 0 deletions api/config/packages/performance_test/web_profiler.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
imports:
- resource: ../test/web_profiler.yaml
22 changes: 22 additions & 0 deletions api/config/packages/security.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,25 @@ when@test:
cost: 4 # Lowest possible value for bcrypt
time_cost: 3 # Lowest possible value for argon
memory_cost: 10 # Lowest possible value for argon
when@performance_test:
security:
password_hashers:
# By default, password hashers are resource intensive and take time. This is
# important to generate secure password hashes. In tests however, secure hashes
# are not important, waste resources and increase test times. The following
# reduces the work factor to the lowest possible values.
App\Entity\User:
algorithm: auto
cost: 4 # Lowest possible value for bcrypt
time_cost: 3 # Lowest possible value for argon
memory_cost: 10 # Lowest possible value for argon
PasswordResetKey:
algorithm: auto
cost: 4 # Lowest possible value for bcrypt
time_cost: 3 # Lowest possible value for argon
memory_cost: 10 # Lowest possible value for argon
EmailVerification:
algorithm: auto
cost: 4 # Lowest possible value for bcrypt
time_cost: 3 # Lowest possible value for argon
memory_cost: 10 # Lowest possible value for argon
136 changes: 136 additions & 0 deletions api/fixtures/performance_test/activities.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
App\Entity\Activity:
additional_activity_{1..400}:
camp: '@additionalCamp_<current()>'
title: 'Activity <current()>'
location: <word()>
rootContentNode: '@additional_columnLayout1_<current()>'
category: '@additionalCategoryForCampNumber1_<current()>'
additional_activity_camp1_{1..200}:
camp: '@camp1'
title: 'Activity <current()>'
location: <word()>
rootContentNode: '@additional_columnLayout_camp1_<current()>'
category: '@category1'

App\Entity\ScheduleEntry:
additional_scheduleEntry1_{1..400}:
period: '@additionalPeriod_<current()>'
activity: '@additional_activity_<current()>'
startOffset: 480
endOffset: 540
additional_scheduleEntry2_{1..400}:
period: '@additionalPeriod_<current()>'
activity: '@additional_activity_<current()>'
startOffset: 1980
endOffset: 2040
additional_scheduleEntry_camp1_{1..200}:
period: '@period1'
activity: '@additional_activity_camp1_<current()>'
startOffset: 480
endOffset: 540

# Root node
App\Entity\ContentNode\ColumnLayout:
additional_columnLayout1_{1..400}:
root: '@self'
parent: null
slot: null
position: 0
data: { columns: [{ slot: '1', width: 12 }] }
instanceName: 'columnLayoutRoot<current()>'
contentType: '@contentTypeColumnLayout'
additional_columnLayout_camp1_{1..200}:
root: '@self'
parent: null
slot: null
position: 0
data: { columns: [ { slot: '1', width: 12 } ] }
instanceName: 'columnLayoutRoot<current()>'
contentType: '@contentTypeColumnLayout'

# Reponsive layout
App\Entity\ContentNode\ResponsiveLayout:
additional_responsiveLayout1_{1..400}:
root: '@additional_columnLayout1_<current()>'
parent: '@additional_columnLayout1_<current()>'
slot: '1'
position: 0
data: { items: [{ slot: 'main' }, { slot: 'aside-top' }, { slot: 'aside-bottom' }] }
instanceName: 'responsiveLayout<current()>'
contentType: '@contentTypeResponsiveLayout'
additional_responsiveLayout_camp1_{1..200}:
root: '@additional_columnLayout_camp1_<current()>'
parent: '@additional_columnLayout_camp1_<current()>'
slot: '1'
position: 0
data: { items: [ { slot: 'main' }, { slot: 'aside-top' }, { slot: 'aside-bottom' } ] }
instanceName: 'responsiveLayout<current()>'
contentType: '@contentTypeResponsiveLayout'

App\Entity\ContentNode\MultiSelect:
additional_multiSelect1_{1..400}:
root: '@additional_columnLayout1_<current()>'
parent: '@additional_responsiveLayout1_<current()>'
slot: 'aside-top'
position: 0
instanceName: 'multiSelect<current()>'
contentType: '@contentTypeMultiSelect'
data: { options: { 'key1': { 'checked': true }, 'key2': { 'checked': true } } }
additional_multiSelect_camp1_{1..200}:
root: '@additional_columnLayout_camp1_<current()>'
parent: '@additional_responsiveLayout_camp1_<current()>'
slot: 'aside-top'
position: 0
instanceName: 'multiSelect<current()>'
contentType: '@contentTypeMultiSelect'
data: { options: { 'key1': { 'checked': true }, 'key2': { 'checked': true } } }

App\Entity\ContentNode\MaterialNode:
additional_materialNode1_{1..400}:
root: '@additional_columnLayout1_<current()>'
parent: '@additional_responsiveLayout1_<current()>'
slot: 'aside-top'
position: 1
instanceName: 'materialNode<current()>'
contentType: '@contentTypeMaterial'
additional_materialNode_camp1_{1..200}:
root: '@additional_columnLayout_camp1_<current()>'
parent: '@additional_responsiveLayout_camp1_<current()>'
slot: 'aside-top'
position: 1
instanceName: 'materialNode<current()>'
contentType: '@contentTypeMaterial'

App\Entity\ContentNode\SingleText:
additional_singleText1_{1..400}:
root: '@additional_columnLayout1_<current()>'
parent: '@additional_responsiveLayout1_<current()>'
slot: 'aside-top'
position: 2
instanceName: 'singleText<current()>'
contentType: '@contentTypeNotes'
data: { html: <word()> }
additional_safetyConcept1_{1..400}:
root: '@additional_columnLayout1_<current()>'
parent: '@additional_responsiveLayout1_<current()>'
slot: 'aside-top'
position: 3
instanceName: 'safetyConcept<current()>'
contentType: '@contentTypeSafetyConcept'
data: { html: <sentence()> }
additional_singleText_camp1_{1..200}:
root: '@additional_columnLayout_camp1_<current()>'
parent: '@additional_responsiveLayout_camp1_<current()>'
slot: 'aside-top'
position: 2
instanceName: 'singleText<current()>'
contentType: '@contentTypeNotes'
data: { html: <word()> }
additional_safetyConcept_camp1_{1..200}:
root: '@additional_columnLayout_camp1_<current()>'
parent: '@additional_responsiveLayout_camp1_<current()>'
slot: 'aside-top'
position: 3
instanceName: 'safetyConcept<current()>'
contentType: '@contentTypeSafetyConcept'
data: { html: <sentence()> }
13 changes: 13 additions & 0 deletions api/fixtures/performance_test/activity-progress-labels.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
App\Entity\ActivityProgressLabel:
additional_activityProgressLabel1_{1..400}:
camp: '@additionalCamp_<current()>'
position: 0
title: 'In Planung'
additional_activityProgressLabel2_{1..400}:
camp: '@additionalCamp_<current()>'
position: 1
title: 'Geplant'
additional_activityProgressLabel_camp1_{3..5}:
camp: '@camp1'
position: <current()>
title: <name()>
7 changes: 7 additions & 0 deletions api/fixtures/performance_test/activityResponsibles.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
App\Entity\ActivityResponsible:
additionalActivityResponsible_{1..400}:
campCollaboration: '@additionalCampCollaboration_<current()>'
activity: '@additional_activity_<current()>'
additionalActivityResponsible_camp1_{1..200}:
campCollaboration: '@additionalCampCollaboration_camp1_1'
activity: '@additional_activity_camp1_<current()>'
11 changes: 11 additions & 0 deletions api/fixtures/performance_test/campCollaborations.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
App\Entity\CampCollaboration:
additionalCampCollaboration_{1..400}:
user: '@additionalUser_<current()>'
camp: '@additionalCamp_<current()>'
status: established
role: manager
additionalCampCollaboration_camp1_{1..10}:
user: '@additionalUser_<current()>'
camp: '@camp1'
status: established
role: manager
13 changes: 13 additions & 0 deletions api/fixtures/performance_test/camps.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
App\Entity\Camp:
additionalCamp_{1..400}:
name: <word()>
title: <word()>
motto: <sentence()>
addressName: <word()>
addressStreet: <address()>
addressZipcode: <postcode()>
addressCity: <city()>
owner: '@admin'
creator: '@admin'
isPrototype: false
campPrototypeId: null
Loading