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
175 changes: 175 additions & 0 deletions .github/workflows/performance.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
name: Performance Tests

on:
schedule:
- cron: '0 2 * * *'
push:
branches: [master]
paths:
- 'app/Http/Controllers/Api/**'
- 'app/Http/Middleware/**'
- 'app/Services/**'
- 'routes/api.php'
workflow_dispatch:
inputs:
base_url:
description: 'Base URL for performance testing'
required: false
default: 'http://127.0.0.1:8000'
vus:
description: 'Number of virtual users'
required: false
default: '10'

jobs:
performance-tests:
runs-on: ubuntu-latest
if: >
github.event_name == 'schedule' ||
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'push' && contains(github.event.head_commit.message, '[perf]'))

services:
mysql:
image: mysql:8.0
env:
MYSQL_DATABASE: testing_perf
MYSQL_ROOT_PASSWORD: secret
ports:
- 3306:3306
options: >-
--health-cmd="mysqladmin ping --silent"
--health-interval=10s
--health-timeout=5s
--health-retries=3

steps:
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.4'
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, tidy
coverage: none

- uses: actions/checkout@v4

- name: Copy .env
run: php -r "file_exists('.env') || copy('.env.example', '.env');"

- name: Install Dependencies
run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist

- name: Generate key
run: php artisan key:generate && php artisan jwt:secret

- name: Directory Permissions
run: chmod -R 777 storage bootstrap/cache

- name: Set Installed State
run: touch storage/installed

- name: Extract database testing
run: |
tar -xzf database/database_test.sql.tar.gz -C database

- name: Wait for MySQL
run: sleep 15

- name: Import SQL file into MySQL
run: |
mysql -h 127.0.0.1 -P 3306 -u root -psecret testing_perf < ./database/database_test.sql

- name: Run migrations
env:
DB_CONNECTION: mysql
DB_DATABASE: testing_perf
DB_USERNAME: root
DB_PASSWORD: secret
run: php artisan migrate --force

- name: Seed test admin user
env:
DB_CONNECTION: mysql
DB_DATABASE: testing_perf
DB_USERNAME: root
DB_PASSWORD: secret
run: |
php artisan tinker --execute="
use App\Models\User;
use Database\Seeders\RoleSpatieSeeder;
\$user = User::firstOrCreate(
['email' => 'admin@mail.com'],
[
'name' => 'Administrator',
'password' => bcrypt('Admin123!'),
'gender' => 'Male',
'address' => 'Jakarta',
'status' => 1,
]
);
\$user->forceFill(['status' => 1])->save();
if (!class_exists(RoleSpatieSeeder::class)) {
(new RoleSpatieSeeder())->run();
}
\$user->assignRole('super-admin');
echo 'Admin user seeded: ' . \$user->email;
"

- name: Start Laravel Server
run: php artisan serve --env=testing --host=0.0.0.0 --port=8000 &
env:
DB_CONNECTION: mysql
DB_DATABASE: testing_perf
DB_USERNAME: root
DB_PASSWORD: secret

- name: Wait for server
run: sleep 5

- name: Install k6
uses: grafana/install-k6-action@v1
with:
version: 'v0.49.0'

- name: Run Performance Test
run: |
K6_BASE_URL=${{ github.event.inputs.base_url || 'http://127.0.0.1:8000' }} \
K6_VUS=${{ github.event.inputs.vus || '10' }} \
k6 run tests/performance/load-test.js
env:
DB_CONNECTION: mysql
DB_DATABASE: testing_perf
DB_USERNAME: root
DB_PASSWORD: secret
continue-on-error: false

- name: Run Rate Limit Test
run: |
K6_BASE_URL=${{ github.event.inputs.base_url || 'http://127.0.0.1:8000' }} \
k6 run tests/performance/rate-limit-test.js
env:
DB_CONNECTION: mysql
DB_DATABASE: testing_perf
DB_USERNAME: root
DB_PASSWORD: secret

- name: Upload Performance Report
if: always()
uses: actions/upload-artifact@v4
with:
name: performance-report
path: tests/performance/*.json
retention-days: 30

- name: Summary
if: always()
run: |
echo "## Performance Test Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ -f tests/performance/report.json ]; then
echo '```json' >> $GITHUB_STEP_SUMMARY
cat tests/performance/report.json >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
else
echo "No performance report generated." >> $GITHUB_STEP_SUMMARY
fi
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
run: npm install

- name: Install Playwright Browsers
run: npx playwright install
run: npm install playwright && npx playwright install

- name: Generate key
run: php artisan key:generate && php artisan jwt:secret
Expand Down
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ public/error_log
/playwright-report/
.env.e2e

# Performance Testing (k6)
/tests/performance/report.json
/tests/performance/rate-limit-report.json
/tests/performance/k6-results.json

# Pest Browser Testing
/tests/Browser/screenshots
/tests/Browser/console
Expand Down
2 changes: 1 addition & 1 deletion .phpunit.cache/test-results

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions catatan_rilis.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Terimakasih [isi disini] yang telah berkontribusi langsung mengembangkan aplikas
5. [#1673](https://github.com/OpenSID/OpenDK/issues/1673) Contract tests consumer-driven antara OpenSID (consumer) dan OpenDK (provider).
6. [#1675](https://github.com/OpenSID/OpenDK/issues/1675) Penambahan unit & integration tests untuk lifecycle API key.
7. [#1676](https://github.com/OpenSID/OpenDK/issues/1676) Workflow integration CI/CD pipeline.
8. [#1677](https://github.com/OpenSID/OpenDK/issues/1677) Penambahan End-to-end (E2E) dan Performance testing untuk alur sinkronisasi data.

#### CATATAN TAMBAHAN

Expand Down
51 changes: 1 addition & 50 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 4 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,15 @@
"test": "php vendor/bin/pest",
"test:parallel": "php vendor/bin/pest --parallel",
"test:browser": "./tests/browser-test.sh",
"test:browser:sync": "php vendor/bin/pest --testsuite=Browser --group=sync-flow",
"test:coverage": "php vendor/bin/pest --coverage",
"test:e2e": "playwright test",
"test:e2e:headed": "playwright test --headed",
"test:e2e:ui": "playwright test --ui",
"test:e2e:debug": "playwright test --debug",
"test:e2e:report": "playwright show-report",
"test:perf": "k6 run tests/performance/load-test.js",
"test:perf:rate-limit": "k6 run tests/performance/rate-limit-test.js",
"test:perf:ci": "k6 run --out json=tests/performance/k6-results.json tests/performance/load-test.js",
"test:contract": "php vendor/bin/pest tests/Contract --group=contract"
},
"devDependencies": {
"@playwright/test": "^1.56.1",
"@shufo/prettier-plugin-blade": "^1.15.0",
"prettier": "^3.6.0"
},
"dependencies": {
"playwright": "^1.58.2"
}
}
15 changes: 12 additions & 3 deletions resources/views/auth/login.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
<div class="tab-content" style="padding-top: 15px;">
<!-- Password Login Tab -->
<div role="tabpanel" class="tab-pane active" id="password-login">
<form method="POST" action="{{ route('login') }}">
<form method="POST" action="{{ route('login') }}" data-testid="login-form">
@csrf
<div class="form-group has-feedback {{ $errors->has('email') ? ' has-error' : '' }}">
<div class="input-group">
Expand All @@ -64,6 +64,7 @@ class="form-control"
required
autofocus
placeholder="Email"
data-testid="login-email"
>
@if ($errors->has('email'))
<span class="help-block">
Expand All @@ -75,7 +76,15 @@ class="form-control"
</div>
<div class="form-group has-feedback {{ $errors->has('password') ? ' has-error' : '' }}">
<div class="input-group">
<input id="password" type="password" class="form-control" name="password" required placeholder="Password">
<input
id="password"
type="password"
class="form-control"
name="password"
required
placeholder="Password"
data-testid="login-password"
>
@if ($errors->has('password'))
<span class="help-block">
<strong>{{ $errors->first('password') }}</strong>
Expand All @@ -97,7 +106,7 @@ class="form-control"
</div>
<!-- /.col -->
<div class="col-xs-4">
<button type="submit" class="btn btn-primary btn-block btn-flat">Sign In</button>
<button type="submit" class="btn btn-primary btn-block btn-flat" data-testid="login-submit">Sign In</button>
</div>
<!-- /.col -->
</div>
Expand Down
Loading