[AZ-189] [AZ-190] [AZ-191] [AZ-192] [AZ-193] [AZ-194] [AZ-195] Add e2e blackbox test suite

Made-with: Cursor
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-04-16 06:25:36 +03:00
parent 1b38e888e1
commit d320d6dd59
98 changed files with 6883 additions and 1 deletions
@@ -0,0 +1,36 @@
# CI/CD Pipeline
## Woodpecker CI
### Pipeline: `.woodpecker/build-arm.yml`
**Triggers**: Push or manual trigger on branches `dev`, `stage`, `main`.
**Platform**: ARM64
**Steps**:
1. **build-push**: Uses `docker` image, builds the Dockerfile, tags based on branch, pushes to local registry.
### Tag Strategy
```
main → localhost:5000/admin:arm
stage → localhost:5000/admin:stage-arm
dev → localhost:5000/admin:dev-arm
```
### Manual Deploy
`deploy.cmd` script (for manual/local builds):
```
docker build -t docker.azaion.com/api .
docker login docker.azaion.com
docker push docker.azaion.com/api
```
## Observations
- No automated testing step in the CI pipeline (build only, no test run).
- ARM64-only builds — no x86/amd64 pipeline.
- No staging or production deployment automation beyond docker push.
- Two registries: `localhost:5000` (CI) and `docker.azaion.com` (manual deploy) — not synchronized.
@@ -0,0 +1,28 @@
# Containerization
## Dockerfile
Multi-stage build targeting .NET 10.0:
1. **Base stage** (`mcr.microsoft.com/dotnet/aspnet:10.0`): Runtime image, exposes port 8080.
2. **Build stage** (`mcr.microsoft.com/dotnet/sdk:10.0`): Restores packages, builds release configuration. Supports cross-platform builds via `$BUILDPLATFORM` and `$TARGETARCH`.
3. **Publish stage**: Publishes with `UseAppHost=false`, targets Linux with specified architecture.
4. **Final stage**: Copies published output, sets entrypoint to `dotnet Azaion.AdminApi.dll`.
## Container Registry
- Private registry: `docker.azaion.com`
- Deploy command: `docker build -t docker.azaion.com/api . && docker push docker.azaion.com/api`
- CI registry: `localhost:5000` (Woodpecker CI local registry)
## Tags
| Branch | Tag |
|--------|-----|
| `main` | `arm` |
| `dev` | `dev-arm` |
| `stage` | `stage-arm` |
## Docker Test
A placeholder `docker.test/Dockerfile` exists (`FROM alpine:latest; CMD echo hello`) — appears unused.
@@ -0,0 +1,44 @@
# Environment Strategy
## Environments
| Environment | Infrastructure | Config Source | Swagger |
|-------------|---------------|---------------|---------|
| Development | Local machine | appsettings.json / env vars | Enabled |
| Production | Linux server (self-hosted) | Environment variables | Disabled |
## Configuration
### appsettings.json Defaults
- `ResourcesConfig`: ResourcesFolder=`"Content"`, SuiteInstallerFolder=`"suite"`, SuiteStageInstallerFolder=`"suite-stage"`
- `JwtConfig`: Issuer=`"AzaionApi"`, Audience=`"Annotators/OrangePi/Admins"`, TokenLifetimeHours=`4`
- `ConnectionStrings` and `JwtConfig.Secret` are NOT in appsettings — must be provided via environment variables
Configuration is loaded via ASP.NET Core's `IConfiguration` with the following sections:
| Section | Purpose | Example Env Var |
|---------|---------|----------------|
| `ConnectionStrings.AzaionDb` | Reader DB connection | `ASPNETCORE_ConnectionStrings__AzaionDb` |
| `ConnectionStrings.AzaionDbAdmin` | Admin DB connection | `ASPNETCORE_ConnectionStrings__AzaionDbAdmin` |
| `JwtConfig.Secret` | JWT signing key | `ASPNETCORE_JwtConfig__Secret` |
| `JwtConfig.Issuer` | Token issuer | — |
| `JwtConfig.Audience` | Token audience | — |
| `JwtConfig.TokenLifetimeHours` | Token TTL | — |
| `ResourcesConfig.ResourcesFolder` | File storage root | — |
| `ResourcesConfig.SuiteInstallerFolder` | Prod installer dir | — |
| `ResourcesConfig.SuiteStageInstallerFolder` | Stage installer dir | — |
## Infrastructure Scripts (`env/`)
| Directory | Purpose |
|-----------|---------|
| `env/db/` | PostgreSQL install, role creation, schema DDL, migrations |
| `env/api/` | API server setup (Nginx reverse proxy, container management) |
| `env/rabbit/` | RabbitMQ install + config (not used by this API) |
| `env/cdn/` | MinIO object storage setup (not used by this API) |
## Database
- PostgreSQL on custom port 4312 (security through obscurity)
- Three DB roles: `azaion_superadmin` (owner), `azaion_admin` (read/write), `azaion_reader` (read-only)
- Schema managed via SQL scripts, no ORM migrations
@@ -0,0 +1,38 @@
# Observability
## Logging
| Aspect | Implementation |
|--------|---------------|
| Framework | Serilog 4.1.0 |
| Sinks | Console, Rolling File (`logs/log.txt`, daily) |
| Minimum Level | Information |
| Enrichment | `FromLogContext` |
### Log Sources
| Source | Level | Content |
|--------|-------|---------|
| BusinessExceptionHandler | WARN | Business exceptions with message |
| ResourcesService | INFO | Successful file saves |
| DbFactory (linq2db trace) | INFO | SQL query text (via `Console.WriteLine`) |
## Metrics
No metrics collection configured (no Prometheus, Application Insights, or similar).
## Health Checks
No health check endpoint configured.
## Tracing
No distributed tracing configured.
## Observations
- Logging is minimal — no structured request/response logging.
- No health check endpoint for container orchestration or load balancer probes.
- SQL trace goes directly to `Console.WriteLine`, not through Serilog.
- No log correlation (request IDs, trace IDs).
- No alerting or monitoring infrastructure.