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
13 changes: 13 additions & 0 deletions .docker/test/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
FROM php:7.4-cli-bullseye

RUN apt-get update -q \
&& apt-get install -y -q --no-install-recommends \
git unzip libssl-dev libcurl4-openssl-dev libzip-dev \
&& docker-php-ext-install pdo pdo_mysql \
&& docker-php-ext-configure curl \
&& docker-php-ext-install curl \
&& rm -rf /var/lib/apt/lists/*

COPY --from=composer:2 /usr/bin/composer /usr/bin/composer

WORKDIR /app
11 changes: 11 additions & 0 deletions .docker/test/api/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FROM php:7.4-apache-bullseye

RUN apt-get update -q \
&& apt-get install -y -q --no-install-recommends \
libssl-dev libcurl4-openssl-dev wget \
&& docker-php-ext-configure curl \
&& docker-php-ext-install pdo pdo_mysql curl \
&& a2enmod headers setenvif \
&& rm -rf /var/lib/apt/lists/*

COPY .docker/test/api/apache.conf /etc/apache2/sites-available/000-default.conf
15 changes: 15 additions & 0 deletions .docker/test/api/apache.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<VirtualHost *:80>
DocumentRoot /var/www/api

# Pass the Authorization header through to PHP (same as production VirtualHost)
SetEnvIf Authorization "(.+)" HTTP_AUTHORIZATION=$1

<Directory /var/www/api>
Options FollowSymLinks
AllowOverride None
Require all granted
# FallbackResource serves index.php for any URI that doesn't map to a file,
# while preserving REQUEST_URI — so Slim 2 routing works correctly.
FallbackResource /index.php
</Directory>
</VirtualHost>
58 changes: 58 additions & 0 deletions .github/workflows/tests_phpunit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: Tests

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
# ---------------------------------------------------------------------------
# Unit tests — no database required
# ---------------------------------------------------------------------------
unit:
name: Unit tests (PHP ${{ matrix.php }})
runs-on: ubuntu-latest

strategy:
matrix:
php: [ "7.4" ]

steps:
- uses: actions/checkout@v4

- name: Set up PHP ${{ matrix.php }}
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: pdo_mysql, pdo_sqlite, sqlite3, dom, mbstring, json, simplexml, libxml, curl
coverage: none

- name: Install dependencies
working-directory: api
run: composer install --no-interaction --prefer-dist --ignore-platform-reqs

- name: Run unit tests
working-directory: api
run: vendor/bin/phpunit --configuration phpunit.xml --testsuite Unit

# ---------------------------------------------------------------------------
# Functional tests — Apache/PHP 7.4 + MySQL 8.0 via Docker Compose
# ---------------------------------------------------------------------------
functional:
name: Functional tests
runs-on: ubuntu-latest
needs: unit

steps:
- uses: actions/checkout@v4

- name: Build test images
run: docker compose -f docker-compose.test.yml build

- name: Run functional tests
run: docker compose -f docker-compose.test.yml run --rm phpunit

- name: Tear down
if: always()
run: docker compose -f docker-compose.test.yml down -v
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ api/config.php
/misc/illuminate_queries.log
.vagrant
/docker-compose.override.yaml
api/.phpunit.result.cache
106 changes: 106 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

This is the **GLPI Plugin Directory** — a web application for browsing and managing plugins for the GLPI IT management system. It consists of:

- `api/` — PHP REST API built on Slim 2 + Eloquent ORM
- `frontend/` — AngularJS 1 SPA built with Grunt
- `specs/` — Modernization specs and test plans (unit, functional, e2e)
- `misc/` — Background task runner and DB initialization scripts

The project is in **active modernization** (Step 1: adding test coverage is in progress). The stack is intentionally legacy (Slim 2, AngularJS 1) and will be upgraded in later steps.

## Commands

### API (PHP)

```bash
cd api
composer install # Install dependencies
vendor/bin/phpunit # Run all tests
vendor/bin/phpunit --testsuite Unit # Unit tests only (no DB)
vendor/bin/phpunit --testsuite Functional # Functional tests (requires MySQL)
vendor/bin/phpunit tests/Unit/SomeTest.php # Single test file
```

Functional tests require a MySQL database. Default credentials (overridable via env vars):
- DB: `glpi_plugins_functional_test`, user: `glpi`, pass: `glpi`, host: `localhost`
- Env vars: `TEST_DB_HOST`, `TEST_DB_NAME`, `TEST_DB_USER`, `TEST_DB_PASS`

### Frontend (JavaScript)

```bash
cd frontend
npm install && bower install # Install dependencies
grunt build # Build production output to dist/
grunt serve # Dev server at http://localhost:9000
grunt test # Run Karma/Jasmine tests
```

### Docker

```bash
docker-compose up -d # Start dev environment
docker exec -it plugins.glpi-project.org bash # Enter container
# Inside container: Apache on :8080, Node dev server on :9000
```

### Background Tasks

```bash
php misc/run_tasks.php # Run all tasks (plugin updates, token cleanup)
php misc/run_tasks.php -k genericobject -t update # Update specific plugin by key
php misc/run_tasks.php -i 44 -t update # Update plugin by DB id
```

## Architecture

### API (Slim 2)

Entry point: `api/index.php` — initializes Illuminate DB capsule, Slim app, OAuth2 resource server, then `require`s all files from `src/endpoints/`.

```
api/src/
├── core/ # Tool.php (request/response helpers), DB.php, Mailer.php, PaginatedCollection.php, ValidableXMLPluginDescription.php
├── endpoints/ # One file per resource (Plugin.php, User.php, Author.php, OAuth.php, Tags.php, …)
├── models/ # Eloquent ORM models (Plugin, User, Author, PluginVersion, OAuth tokens, …)
├── exceptions/ # ErrorResponse base + subclasses (InvalidField, ResourceNotFound, …)
└── oauthserver/ # OAuthHelper.php — league/oauth2-server v4.1 storage & factory
```

**Key patterns:**
- Endpoint files are procedural PHP modules, not classes — they register Slim routes directly.
- Pagination uses HTTP headers (`x-range`, `x-lang`) rather than query params.
- OAuth2 supports `password`, `refresh_token`, and `client_credentials` grants.
- Config is loaded from `api/config.php` (copy from `api/config.example.php`).

### Tests

**Unit tests** (`api/tests/Unit/`) — no database, use Mockery. Cover `core/`, `models/`, `exceptions/`, `oauthserver/`.

**Functional tests** (`api/tests/Functional/`) — spin up PHP built-in server as subprocess, send real HTTP requests via Guzzle. Each test class reloads seeds (`tests/Functional/seeds.sql`) and wraps tests in a rolled-back transaction. Schema is initialized once per suite from `tests/Functional/schema.sql`.

**Frontend tests** (`frontend/test/spec/`) — Karma + Jasmine, cover controllers, services, directives, filters.

### Frontend (AngularJS 1)

SPA routed via `ng-route`. API endpoint configured in `frontend/app/scripts/conf.js` (copy from `conf.example.js`). Build output goes to `frontend/dist/`.

## CI/CD

GitHub Actions (`.github/workflows/tests_phpunit.yml`):
- **Unit**: PHP 8.2, 8.3, 8.4 matrix — no database
- **Functional**: PHP 8.4 + MySQL 8.0 — depends on unit passing
- Triggers on push/PR to `master`

## Spec Files

Detailed test specifications live in `specs/testing/`:
- `unit.md` — what unit tests should cover
- `functional.md` — what functional tests should cover
- `e2e.md` — E2E test plan

`specs/api/endpoints.md` is the full REST API reference including auth scopes, request/response shapes, and pagination behavior.
25 changes: 24 additions & 1 deletion api/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,31 @@
"API\\Exception\\": "src/exceptions"
}
},
"require-dev": {
"guzzlehttp/guzzle": "^6.0",
"mockery/mockery": "^1.6",
"phpunit/phpunit": "^9.5",
"symfony/process": "^5.0"
},
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/"
}
},
"extra": {
"upgrade-notes": [
"slim/slim is pinned to ~2.0 — index.php has a get_magic_quotes_gpc() polyfill that must be removed when upgrading to Slim 3+.",
"illuminate/database is pinned to 5.1.* — vendor/nesbot/carbon Carbon.php has a manual PHP 8.2 compat patch (getLastErrors() returning false) that must be removed when upgrading Eloquent/Carbon."
]
},
"config": {
"optimize-autoloader": true,
"sort-packages": true
"sort-packages": true,
"platform": {
"php": "7.4.0"
},
"allow-plugins": {
"kylekatarnls/update-helper": true
}
}
}
Loading
Loading