docs
This commit is contained in:
35
docs/README.md
Normal file
35
docs/README.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# Документация Quoter
|
||||
|
||||
## 📚 Оглавление
|
||||
|
||||
### Основные разделы
|
||||
- [Как это работает](./how-it-works.md) - Подробное описание архитектуры и процессов
|
||||
- [API Reference](./api-reference.md) - Полная документация API
|
||||
- [Развертывание](./deployment.md) - Инструкции по развертыванию
|
||||
- [Конфигурация](./configuration.md) - Настройка переменных окружения
|
||||
- [Мониторинг](./monitoring.md) - Логирование и мониторинг
|
||||
|
||||
### Технические детали
|
||||
- [Архитектура](./architecture.md) - Техническая архитектура системы
|
||||
- [База данных](./database.md) - Структура Redis и схемы данных
|
||||
- [S3 интеграция](./s3-integration.md) - Работа с S3/Storj
|
||||
- [Обработка изображений](./image-processing.md) - Создание миниатюр и оверлеев
|
||||
- [Безопасность](./security.md) - Аутентификация и авторизация
|
||||
|
||||
### Разработка
|
||||
- [Разработка](./development.md) - Настройка среды разработки
|
||||
- [Тестирование](./testing.md) - Руководство по тестированию
|
||||
- [Contributing](./contributing.md) - Руководство для контрибьюторов
|
||||
|
||||
## 🚀 Быстрый старт
|
||||
|
||||
1. Установите зависимости: `cargo build`
|
||||
2. Настройте переменные окружения (см. [Конфигурация](./configuration.md))
|
||||
3. Запустите сервер: `cargo run`
|
||||
4. Проверьте API: `curl http://localhost:8080/`
|
||||
|
||||
## 📋 Требования
|
||||
|
||||
- Rust 1.70+
|
||||
- Redis 6.0+
|
||||
- Доступ к S3/Storj API
|
||||
169
docs/api-reference.md
Normal file
169
docs/api-reference.md
Normal file
@@ -0,0 +1,169 @@
|
||||
# API Reference
|
||||
|
||||
## Обзор
|
||||
|
||||
Quoter предоставляет REST API для загрузки файлов, управления квотами и получения файлов с автоматической генерацией миниатюр.
|
||||
|
||||
## Базовый URL
|
||||
|
||||
```
|
||||
http://localhost:8080
|
||||
```
|
||||
|
||||
## Аутентификация
|
||||
|
||||
Все API endpoints (кроме получения файлов) требуют аутентификации через заголовок `Authorization`:
|
||||
|
||||
```
|
||||
Authorization: Bearer <your-jwt-token>
|
||||
```
|
||||
|
||||
## Endpoints
|
||||
|
||||
### 1. Проверка состояния сервера
|
||||
|
||||
#### GET /
|
||||
Проверяет работоспособность сервера.
|
||||
|
||||
**Ответ:**
|
||||
```
|
||||
200 OK
|
||||
ok
|
||||
```
|
||||
|
||||
### 2. Загрузка файлов
|
||||
|
||||
#### POST /
|
||||
Загружает файл в S3 хранилище.
|
||||
|
||||
**Заголовки:**
|
||||
```
|
||||
Authorization: Bearer <token>
|
||||
Content-Type: multipart/form-data
|
||||
```
|
||||
|
||||
**Параметры:**
|
||||
- `file` - файл для загрузки
|
||||
|
||||
**Ответ:**
|
||||
```
|
||||
200 OK
|
||||
filename.ext
|
||||
```
|
||||
|
||||
**Ошибки:**
|
||||
- `401 Unauthorized` - неверный токен
|
||||
- `413 Payload Too Large` - превышена квота
|
||||
- `415 Unsupported Media Type` - неподдерживаемый тип файла
|
||||
|
||||
### 3. Получение файлов
|
||||
|
||||
#### GET /{filename}
|
||||
Получает файл по имени.
|
||||
|
||||
**Параметры запроса:**
|
||||
- `s=<shout_id>` - добавляет оверлей с данными shout (только для изображений)
|
||||
|
||||
**Примеры:**
|
||||
```
|
||||
GET /image.jpg
|
||||
GET /image.jpg?s=123
|
||||
GET /image_300.jpg
|
||||
GET /image_300.jpg/webp
|
||||
```
|
||||
|
||||
### 4. Управление квотами
|
||||
|
||||
#### GET /quota
|
||||
Получает информацию о квоте пользователя.
|
||||
|
||||
**Параметры запроса:**
|
||||
- `user_id` - ID пользователя
|
||||
|
||||
**Пример:**
|
||||
```
|
||||
GET /quota?user_id=user123
|
||||
```
|
||||
|
||||
**Ответ:**
|
||||
```json
|
||||
{
|
||||
"user_id": "user123",
|
||||
"current_quota": 1073741824,
|
||||
"max_quota": 5368709120
|
||||
}
|
||||
```
|
||||
|
||||
#### POST /quota/increase
|
||||
Увеличивает квоту пользователя.
|
||||
|
||||
**Тело запроса:**
|
||||
```json
|
||||
{
|
||||
"user_id": "user123",
|
||||
"additional_bytes": 1073741824
|
||||
}
|
||||
```
|
||||
|
||||
**Ответ:**
|
||||
```json
|
||||
{
|
||||
"user_id": "user123",
|
||||
"current_quota": 2147483648,
|
||||
"max_quota": 5368709120
|
||||
}
|
||||
```
|
||||
|
||||
#### POST /quota/set
|
||||
Устанавливает квоту пользователя.
|
||||
|
||||
**Тело запроса:**
|
||||
```json
|
||||
{
|
||||
"user_id": "user123",
|
||||
"new_quota_bytes": 2147483648
|
||||
}
|
||||
```
|
||||
|
||||
**Ответ:**
|
||||
```json
|
||||
{
|
||||
"user_id": "user123",
|
||||
"current_quota": 2147483648,
|
||||
"max_quota": 5368709120
|
||||
}
|
||||
```
|
||||
|
||||
## Коды ошибок
|
||||
|
||||
| Код | Описание |
|
||||
|-----|----------|
|
||||
| 200 | Успешный запрос |
|
||||
| 400 | Неверные параметры запроса |
|
||||
| 401 | Неавторизованный доступ |
|
||||
| 404 | Файл не найден |
|
||||
| 413 | Превышена квота |
|
||||
| 415 | Неподдерживаемый тип файла |
|
||||
| 500 | Внутренняя ошибка сервера |
|
||||
|
||||
## Примеры использования
|
||||
|
||||
### Загрузка изображения
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/ \
|
||||
-H "Authorization: Bearer your-token" \
|
||||
-F "file=@image.jpg"
|
||||
```
|
||||
|
||||
### Получение миниатюры
|
||||
```bash
|
||||
curl http://localhost:8080/image_300.jpg
|
||||
```
|
||||
|
||||
### Увеличение квоты
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/quota/increase \
|
||||
-H "Authorization: Bearer your-token" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"user_id": "user123", "additional_bytes": 1073741824}'
|
||||
```
|
||||
196
docs/architecture.md
Normal file
196
docs/architecture.md
Normal file
@@ -0,0 +1,196 @@
|
||||
# Архитектура
|
||||
|
||||
## Обзор системы
|
||||
|
||||
Quoter - это микросервис для управления файлами с поддержкой квот, миниатюр и интеграции с S3 хранилищами.
|
||||
|
||||
## Компоненты системы
|
||||
|
||||
```
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ Web Client │ │ Mobile App │ │ API Client │
|
||||
└─────────┬───────┘ └─────────┬───────┘ └─────────┬───────┘
|
||||
│ │ │
|
||||
└──────────────────────┼──────────────────────┘
|
||||
│
|
||||
┌─────────────▼─────────────┐
|
||||
│ Quoter Service │
|
||||
│ (Actix Web Server) │
|
||||
└─────────────┬─────────────┘
|
||||
│
|
||||
┌───────────────────────┼───────────────────────┐
|
||||
│ │ │
|
||||
┌─────▼─────┐ ┌───────▼──────┐ ┌─────▼─────┐
|
||||
│ Redis │ │ Core API │ │ S3/Storj│
|
||||
│ (Quotas & │ │(Auth & Shout)│ │ (Storage) │
|
||||
│ Cache) │ │ │ │ │
|
||||
└───────────┘ └──────────────┘ └───────────┘
|
||||
```
|
||||
|
||||
## Основные модули
|
||||
|
||||
### 1. AppState (`src/app_state.rs`)
|
||||
Центральное состояние приложения, содержащее:
|
||||
- Подключения к Redis, Storj S3, AWS S3
|
||||
- Методы для работы с квотами
|
||||
- Кэширование списка файлов
|
||||
|
||||
### 2. Handlers (`src/handlers/`)
|
||||
Обработчики HTTP запросов:
|
||||
- `upload.rs` - загрузка файлов
|
||||
- `proxy.rs` - получение файлов и генерация миниатюр
|
||||
- `quota.rs` - управление квотами
|
||||
- `serve_file.rs` - обслуживание файлов
|
||||
|
||||
### 3. Auth (`src/auth.rs`)
|
||||
Аутентификация через GraphQL API ядра:
|
||||
- Валидация JWT токенов
|
||||
- Управление файлами пользователей в Redis
|
||||
|
||||
### 4. Core (`src/core.rs`)
|
||||
Интеграция с API ядра:
|
||||
- Получение данных shout для оверлеев
|
||||
|
||||
### 5. Thumbnail (`src/thumbnail.rs`)
|
||||
Обработка изображений:
|
||||
- Создание миниатюр различных размеров
|
||||
- Поддержка различных форматов
|
||||
|
||||
### 6. S3 Utils (`src/s3_utils.rs`)
|
||||
Утилиты для работы с S3:
|
||||
- Загрузка/скачивание файлов
|
||||
- Определение MIME типов
|
||||
- Генерация ключей
|
||||
|
||||
## Поток данных
|
||||
|
||||
### Загрузка файла
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client
|
||||
participant Quoter
|
||||
participant Core API
|
||||
participant Redis
|
||||
participant S3
|
||||
|
||||
Client->>Quoter: POST / (file + token)
|
||||
Quoter->>Core API: Validate token
|
||||
Core API-->>Quoter: User ID
|
||||
Quoter->>Redis: Check quota
|
||||
Redis-->>Quoter: Current quota
|
||||
Quoter->>S3: Upload file
|
||||
S3-->>Quoter: Success
|
||||
Quoter->>Redis: Update quota
|
||||
Quoter->>Redis: Save file info
|
||||
Quoter-->>Client: Filename
|
||||
```
|
||||
|
||||
### Получение файла
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client
|
||||
participant Quoter
|
||||
participant Redis
|
||||
participant S3
|
||||
|
||||
Client->>Quoter: GET /filename
|
||||
Quoter->>Redis: Get file path
|
||||
Redis-->>Quoter: File path
|
||||
Quoter->>S3: Check file exists
|
||||
S3-->>Quoter: File exists
|
||||
Quoter->>S3: Download file
|
||||
S3-->>Quoter: File data
|
||||
Quoter-->>Client: File content
|
||||
```
|
||||
|
||||
## Структура данных
|
||||
|
||||
### Redis схемы
|
||||
|
||||
#### Квоты пользователей
|
||||
```
|
||||
Key: quota:{user_id}
|
||||
Type: String
|
||||
Value: bytes_used (u64)
|
||||
TTL: None (permanent)
|
||||
```
|
||||
|
||||
#### Файлы пользователей
|
||||
```
|
||||
Key: {user_id}
|
||||
Type: Set
|
||||
Value: [filename1, filename2, ...]
|
||||
TTL: None (permanent)
|
||||
```
|
||||
|
||||
#### Маппинг путей файлов
|
||||
```
|
||||
Key: filepath_mapping
|
||||
Type: Hash
|
||||
Field: filename
|
||||
Value: filepath
|
||||
TTL: None (permanent)
|
||||
```
|
||||
|
||||
#### Информация о файлах
|
||||
```
|
||||
Key: files:{filename}
|
||||
Type: String
|
||||
Value: mime_type
|
||||
TTL: None (permanent)
|
||||
```
|
||||
|
||||
### S3 структура
|
||||
|
||||
```
|
||||
bucket/
|
||||
├── original_files/
|
||||
│ ├── image1.jpg
|
||||
│ ├── image2.png
|
||||
│ └── document.pdf
|
||||
├── thumbnails/
|
||||
│ ├── image1_10.jpg
|
||||
│ ├── image1_40.jpg
|
||||
│ ├── image1_110.jpg
|
||||
│ ├── image1_300.jpg
|
||||
│ ├── image1_600.jpg
|
||||
│ ├── image1_800.jpg
|
||||
│ └── image1_1400.jpg
|
||||
└── webp_thumbnails/
|
||||
├── image1_10.jpg/webp
|
||||
├── image1_40.jpg/webp
|
||||
└── ...
|
||||
```
|
||||
|
||||
## Безопасность
|
||||
|
||||
### Аутентификация
|
||||
- JWT токены через GraphQL API ядра
|
||||
- Валидация токенов для всех операций записи
|
||||
|
||||
### Авторизация
|
||||
- Проверка квот перед загрузкой
|
||||
- Изоляция файлов по пользователям
|
||||
|
||||
### CORS
|
||||
- Настроен для кросс-доменных запросов
|
||||
- Поддержка credentials
|
||||
|
||||
## Масштабирование
|
||||
|
||||
### Горизонтальное масштабирование
|
||||
- Stateless архитектура
|
||||
- Redis как общее хранилище состояния
|
||||
- S3 как общее файловое хранилище
|
||||
|
||||
### Производительность
|
||||
- Асинхронная обработка запросов
|
||||
- Кэширование списка файлов
|
||||
- Ленивая генерация миниатюр
|
||||
|
||||
### Мониторинг
|
||||
- Структурированное логирование
|
||||
- Метрики использования квот
|
||||
- Отслеживание ошибок
|
||||
137
docs/configuration.md
Normal file
137
docs/configuration.md
Normal file
@@ -0,0 +1,137 @@
|
||||
# Конфигурация
|
||||
|
||||
## Переменные окружения
|
||||
|
||||
Quoter использует следующие переменные окружения для настройки:
|
||||
|
||||
### Обязательные переменные
|
||||
|
||||
| Переменная | Описание | Пример |
|
||||
|------------|----------|--------|
|
||||
| `REDIS_URL` | URL для подключения к Redis | `redis://localhost:6379` |
|
||||
| `CORE_URL` | URL для подключения к API ядра | `https://api.example.com/graphql` |
|
||||
| `STORJ_ACCESS_KEY` | Ключ доступа к Storj S3 | `your-storj-access-key` |
|
||||
| `STORJ_SECRET_KEY` | Секретный ключ Storj S3 | `your-storj-secret-key` |
|
||||
| `AWS_ACCESS_KEY` | Ключ доступа к AWS S3 | `your-aws-access-key` |
|
||||
| `AWS_SECRET_KEY` | Секретный ключ AWS S3 | `your-aws-secret-key` |
|
||||
|
||||
### Опциональные переменные
|
||||
|
||||
| Переменная | Описание | По умолчанию |
|
||||
|------------|----------|--------------|
|
||||
| `PORT` | Порт для запуска сервера | `8080` |
|
||||
| `STORJ_END_POINT` | Endpoint Storj S3 | `https://gateway.storjshare.io` |
|
||||
| `STORJ_BUCKET_NAME` | Имя bucket в Storj | `discours-io` |
|
||||
| `AWS_END_POINT` | Endpoint AWS S3 | `https://s3.amazonaws.com` |
|
||||
| `RUST_LOG` | Уровень логирования | `info` |
|
||||
|
||||
## Пример .env файла
|
||||
|
||||
```bash
|
||||
# Redis
|
||||
REDIS_URL=redis://localhost:6379
|
||||
|
||||
# Core API
|
||||
CORE_URL=https://api.example.com/graphql
|
||||
|
||||
# Storj S3
|
||||
STORJ_ACCESS_KEY=your-storj-access-key
|
||||
STORJ_SECRET_KEY=your-storj-secret-key
|
||||
STORJ_END_POINT=https://gateway.storjshare.io
|
||||
STORJ_BUCKET_NAME=discours-io
|
||||
|
||||
# AWS S3
|
||||
AWS_ACCESS_KEY=your-aws-access-key
|
||||
AWS_SECRET_KEY=your-aws-secret-key
|
||||
AWS_END_POINT=https://s3.amazonaws.com
|
||||
|
||||
# Server
|
||||
PORT=8080
|
||||
RUST_LOG=info
|
||||
```
|
||||
|
||||
## Настройка Redis
|
||||
|
||||
### Минимальная конфигурация Redis
|
||||
|
||||
```redis
|
||||
# redis.conf
|
||||
maxmemory 2gb
|
||||
maxmemory-policy allkeys-lru
|
||||
save 900 1
|
||||
save 300 10
|
||||
save 60 10000
|
||||
```
|
||||
|
||||
### Проверка подключения
|
||||
|
||||
```bash
|
||||
redis-cli ping
|
||||
```
|
||||
|
||||
## Настройка S3
|
||||
|
||||
### Storj S3
|
||||
|
||||
1. Создайте аккаунт на [Storj](https://storj.io)
|
||||
2. Создайте API ключи в консоли
|
||||
3. Создайте bucket для файлов
|
||||
4. Настройте CORS для bucket:
|
||||
|
||||
```json
|
||||
{
|
||||
"CORSRules": [
|
||||
{
|
||||
"AllowedOrigins": ["*"],
|
||||
"AllowedMethods": ["GET", "POST", "PUT", "DELETE"],
|
||||
"AllowedHeaders": ["*"],
|
||||
"ExposeHeaders": ["ETag"]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### AWS S3
|
||||
|
||||
1. Создайте IAM пользователя с правами S3
|
||||
2. Создайте bucket для файлов
|
||||
3. Настройте CORS аналогично Storj
|
||||
|
||||
## Логирование
|
||||
|
||||
### Уровни логирования
|
||||
|
||||
- `error` - только ошибки
|
||||
- `warn` - предупреждения и ошибки
|
||||
- `info` - информационные сообщения, предупреждения и ошибки
|
||||
- `debug` - отладочная информация
|
||||
- `trace` - максимальная детализация
|
||||
|
||||
### Примеры
|
||||
|
||||
```bash
|
||||
# Только ошибки
|
||||
RUST_LOG=error cargo run
|
||||
|
||||
# Информационные сообщения
|
||||
RUST_LOG=info cargo run
|
||||
|
||||
# Отладка
|
||||
RUST_LOG=debug cargo run
|
||||
```
|
||||
|
||||
## Проверка конфигурации
|
||||
|
||||
Запустите сервер и проверьте логи:
|
||||
|
||||
```bash
|
||||
RUST_LOG=info cargo run
|
||||
```
|
||||
|
||||
Успешный запуск должен показать:
|
||||
|
||||
```
|
||||
[INFO] Started
|
||||
[WARN] caching AWS filelist...
|
||||
[WARN] cached 1234 files
|
||||
```
|
||||
292
docs/contributing.md
Normal file
292
docs/contributing.md
Normal file
@@ -0,0 +1,292 @@
|
||||
# Contributing
|
||||
|
||||
## Спасибо за интерес к Quoter! 🎉
|
||||
|
||||
Мы приветствуем вклад от сообщества. Этот документ содержит руководство по участию в разработке проекта.
|
||||
|
||||
## Как внести свой вклад
|
||||
|
||||
### 1. Сообщить о баге
|
||||
|
||||
Если вы нашли баг, создайте issue с:
|
||||
|
||||
- **Кратким описанием** проблемы
|
||||
- **Шагами для воспроизведения**
|
||||
- **Ожидаемым и фактическим поведением**
|
||||
- **Версией** Rust, Redis, и других зависимостей
|
||||
- **Логами** (если применимо)
|
||||
|
||||
### 2. Предложить новую функциональность
|
||||
|
||||
Для предложения новой функциональности:
|
||||
|
||||
- Опишите проблему, которую решает ваше предложение
|
||||
- Предложите решение
|
||||
- Обсудите альтернативы
|
||||
- Укажите приоритет
|
||||
|
||||
### 3. Внести код
|
||||
|
||||
#### Подготовка
|
||||
|
||||
1. **Fork** репозиторий
|
||||
2. **Clone** ваш fork локально
|
||||
3. Создайте **feature branch**:
|
||||
```bash
|
||||
git checkout -b feature/amazing-feature
|
||||
```
|
||||
|
||||
#### Разработка
|
||||
|
||||
1. **Следуйте стандартам кода**:
|
||||
```bash
|
||||
cargo fmt
|
||||
cargo clippy
|
||||
```
|
||||
|
||||
2. **Добавьте тесты** для новой функциональности
|
||||
|
||||
3. **Обновите документацию** если необходимо
|
||||
|
||||
4. **Проверьте сборку**:
|
||||
```bash
|
||||
cargo build
|
||||
cargo test
|
||||
```
|
||||
|
||||
#### Commit и Push
|
||||
|
||||
1. **Создайте commit** с описательным сообщением:
|
||||
```bash
|
||||
git commit -m "feat: add amazing feature"
|
||||
```
|
||||
|
||||
2. **Push** в ваш fork:
|
||||
```bash
|
||||
git push origin feature/amazing-feature
|
||||
```
|
||||
|
||||
3. **Создайте Pull Request**
|
||||
|
||||
## Стандарты кода
|
||||
|
||||
### Rust
|
||||
|
||||
- Следуйте [Rust Style Guide](https://doc.rust-lang.org/1.0.0/style/style/naming/README.html)
|
||||
- Используйте `cargo fmt` для форматирования
|
||||
- Используйте `cargo clippy` для проверки стиля
|
||||
- Документируйте публичные API
|
||||
|
||||
### Commit Messages
|
||||
|
||||
Используйте [Conventional Commits](https://www.conventionalcommits.org/):
|
||||
|
||||
```
|
||||
<type>[optional scope]: <description>
|
||||
|
||||
[optional body]
|
||||
|
||||
[optional footer(s)]
|
||||
```
|
||||
|
||||
Типы:
|
||||
- `feat:` - новая функциональность
|
||||
- `fix:` - исправление бага
|
||||
- `docs:` - изменения в документации
|
||||
- `style:` - форматирование кода
|
||||
- `refactor:` - рефакторинг
|
||||
- `test:` - добавление тестов
|
||||
- `chore:` - обновление зависимостей
|
||||
|
||||
Примеры:
|
||||
```
|
||||
feat: add user quota management API
|
||||
fix(auth): handle expired tokens properly
|
||||
docs: update API documentation
|
||||
style: format code with cargo fmt
|
||||
```
|
||||
|
||||
### Тестирование
|
||||
|
||||
- **Unit тесты** для всех новых функций
|
||||
- **Интеграционные тесты** для API endpoints
|
||||
- **Тесты производительности** для критических участков
|
||||
- Минимальное покрытие кода: **80%**
|
||||
|
||||
### Документация
|
||||
|
||||
- Обновляйте README.md если необходимо
|
||||
- Добавляйте комментарии к сложному коду
|
||||
- Документируйте API изменения
|
||||
- Обновляйте примеры использования
|
||||
|
||||
## Процесс Pull Request
|
||||
|
||||
### Создание PR
|
||||
|
||||
1. **Заполните шаблон** Pull Request
|
||||
2. **Опишите изменения** подробно
|
||||
3. **Укажите связанные issues**
|
||||
4. **Добавьте скриншоты** если применимо
|
||||
|
||||
### Code Review
|
||||
|
||||
- **Два approval** требуются для merge
|
||||
- **CI/CD** должен пройти успешно
|
||||
- **Code coverage** не должен уменьшиться
|
||||
- **Безопасность** проверяется автоматически
|
||||
|
||||
### После Merge
|
||||
|
||||
- **Feature branch** удаляется автоматически
|
||||
- **Release** создается для значительных изменений
|
||||
- **Документация** обновляется
|
||||
|
||||
## Настройка среды разработки
|
||||
|
||||
### Требования
|
||||
|
||||
- Rust 1.70+
|
||||
- Redis 6.0+
|
||||
- Git
|
||||
|
||||
### Установка
|
||||
|
||||
```bash
|
||||
# Fork и clone
|
||||
git clone https://github.com/YOUR_USERNAME/quoter.git
|
||||
cd quoter
|
||||
|
||||
# Установка зависимостей
|
||||
cargo build
|
||||
|
||||
# Настройка pre-commit hooks
|
||||
cargo install cargo-husky
|
||||
cargo husky install
|
||||
```
|
||||
|
||||
### Локальная разработка
|
||||
|
||||
```bash
|
||||
# Запуск Redis
|
||||
docker run -d -p 6379:6379 redis:7-alpine
|
||||
|
||||
# Настройка переменных окружения
|
||||
cp .env.example .env
|
||||
# Отредактируйте .env
|
||||
|
||||
# Запуск приложения
|
||||
cargo run
|
||||
|
||||
# Запуск тестов
|
||||
cargo test
|
||||
```
|
||||
|
||||
## Структура проекта
|
||||
|
||||
```
|
||||
quoter/
|
||||
├── src/ # Исходный код
|
||||
│ ├── main.rs # Точка входа
|
||||
│ ├── app_state.rs # Состояние приложения
|
||||
│ ├── auth.rs # Аутентификация
|
||||
│ ├── core.rs # API ядра
|
||||
│ ├── handlers/ # HTTP обработчики
|
||||
│ ├── lookup.rs # Поиск файлов
|
||||
│ ├── overlay.rs # Оверлеи
|
||||
│ ├── s3_utils.rs # S3 утилиты
|
||||
│ └── thumbnail.rs # Миниатюры
|
||||
├── docs/ # Документация
|
||||
├── tests/ # Интеграционные тесты
|
||||
├── Cargo.toml # Зависимости
|
||||
└── README.md # Основная документация
|
||||
```
|
||||
|
||||
## Роли в проекте
|
||||
|
||||
### Maintainers
|
||||
|
||||
- **Code review** всех PR
|
||||
- **Release management**
|
||||
- **Architecture decisions**
|
||||
- **Community management**
|
||||
|
||||
### Contributors
|
||||
|
||||
- **Feature development**
|
||||
- **Bug fixes**
|
||||
- **Documentation**
|
||||
- **Testing**
|
||||
|
||||
### Reviewers
|
||||
|
||||
- **Code review** assigned PRs
|
||||
- **Quality assurance**
|
||||
- **Performance review**
|
||||
|
||||
## Коммуникация
|
||||
|
||||
### Issues
|
||||
|
||||
- Используйте **labels** для категоризации
|
||||
- **Assign** issues к себе если работаете над ними
|
||||
- **Update** статус регулярно
|
||||
|
||||
### Discussions
|
||||
|
||||
- **GitHub Discussions** для общих вопросов
|
||||
- **RFC** для значительных изменений
|
||||
- **Architecture** для архитектурных решений
|
||||
|
||||
### Code Review
|
||||
|
||||
- **Будьте конструктивными**
|
||||
- **Объясняйте причины** изменений
|
||||
- **Предлагайте альтернативы**
|
||||
- **Отвечайте на комментарии**
|
||||
|
||||
## Безопасность
|
||||
|
||||
### Отчеты о уязвимостях
|
||||
|
||||
Для критических уязвимостей:
|
||||
|
||||
1. **НЕ создавайте публичный issue**
|
||||
2. **Отправьте email** на security@example.com
|
||||
3. **Опишите уязвимость** подробно
|
||||
4. **Предложите решение** если возможно
|
||||
|
||||
### Безопасность кода
|
||||
|
||||
- **Не коммитьте секреты**
|
||||
- **Валидируйте входные данные**
|
||||
- **Используйте безопасные зависимости**
|
||||
- **Проверяйте код на уязвимости**
|
||||
|
||||
## Лицензия
|
||||
|
||||
Внося код в проект, вы соглашаетесь с тем, что ваш вклад будет лицензирован под MIT License.
|
||||
|
||||
## Благодарности
|
||||
|
||||
Спасибо всем контрибьюторам, которые помогают сделать Quoter лучше! 🙏
|
||||
|
||||
### Способы поддержки
|
||||
|
||||
- **Code contributions**
|
||||
- **Bug reports**
|
||||
- **Feature requests**
|
||||
- **Documentation improvements**
|
||||
- **Community support**
|
||||
- **Financial support** (если применимо)
|
||||
|
||||
## Контакты
|
||||
|
||||
- **Issues**: [GitHub Issues](https://github.com/your-org/quoter/issues)
|
||||
- **Discussions**: [GitHub Discussions](https://github.com/your-org/quoter/discussions)
|
||||
- **Email**: maintainers@example.com
|
||||
- **Chat**: [Discord/Slack] (если есть)
|
||||
|
||||
---
|
||||
|
||||
**Спасибо за ваш вклад в Quoter!** 🚀
|
||||
318
docs/deployment.md
Normal file
318
docs/deployment.md
Normal file
@@ -0,0 +1,318 @@
|
||||
# Развертывание
|
||||
|
||||
## Обзор
|
||||
|
||||
Quoter можно развернуть различными способами в зависимости от ваших потребностей и инфраструктуры.
|
||||
|
||||
## Способы развертывания
|
||||
|
||||
### 1. Docker (Рекомендуется)
|
||||
|
||||
#### Сборка образа
|
||||
|
||||
```bash
|
||||
# Сборка production образа
|
||||
docker build -t quoter:latest .
|
||||
|
||||
# Сборка с тегами
|
||||
docker build -t quoter:v1.0.0 .
|
||||
```
|
||||
|
||||
#### Запуск контейнера
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name quoter \
|
||||
-p 8080:8080 \
|
||||
-e REDIS_URL=redis://redis:6379 \
|
||||
-e CORE_URL=https://api.example.com/graphql \
|
||||
-e STORJ_ACCESS_KEY=your-key \
|
||||
-e STORJ_SECRET_KEY=your-secret \
|
||||
-e AWS_ACCESS_KEY=your-aws-key \
|
||||
-e AWS_SECRET_KEY=your-aws-secret \
|
||||
quoter:latest
|
||||
```
|
||||
|
||||
#### Docker Compose
|
||||
|
||||
Создайте `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
ports:
|
||||
- "6379:6379"
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
command: redis-server --appendonly yes
|
||||
|
||||
quoter:
|
||||
build: .
|
||||
ports:
|
||||
- "8080:8080"
|
||||
environment:
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- CORE_URL=https://api.example.com/graphql
|
||||
- STORJ_ACCESS_KEY=${STORJ_ACCESS_KEY}
|
||||
- STORJ_SECRET_KEY=${STORJ_SECRET_KEY}
|
||||
- AWS_ACCESS_KEY=${AWS_ACCESS_KEY}
|
||||
- AWS_SECRET_KEY=${AWS_SECRET_KEY}
|
||||
- RUST_LOG=info
|
||||
depends_on:
|
||||
- redis
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
redis_data:
|
||||
```
|
||||
|
||||
Запуск:
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### 2. Kubernetes
|
||||
|
||||
#### Deployment
|
||||
|
||||
Создайте `k8s/deployment.yaml`:
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: quoter
|
||||
labels:
|
||||
app: quoter
|
||||
spec:
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: quoter
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: quoter
|
||||
spec:
|
||||
containers:
|
||||
- name: quoter
|
||||
image: quoter:latest
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
env:
|
||||
- name: REDIS_URL
|
||||
value: "redis://redis-service:6379"
|
||||
- name: CORE_URL
|
||||
value: "https://api.example.com/graphql"
|
||||
- name: STORJ_ACCESS_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: quoter-secrets
|
||||
key: storj-access-key
|
||||
- name: STORJ_SECRET_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: quoter-secrets
|
||||
key: storj-secret-key
|
||||
- name: AWS_ACCESS_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: quoter-secrets
|
||||
key: aws-access-key
|
||||
- name: AWS_SECRET_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: quoter-secrets
|
||||
key: aws-secret-key
|
||||
- name: RUST_LOG
|
||||
value: "info"
|
||||
resources:
|
||||
requests:
|
||||
memory: "256Mi"
|
||||
cpu: "250m"
|
||||
limits:
|
||||
memory: "512Mi"
|
||||
cpu: "500m"
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: 8080
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: 8080
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
```
|
||||
|
||||
#### Service
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: quoter-service
|
||||
spec:
|
||||
selector:
|
||||
app: quoter
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 80
|
||||
targetPort: 8080
|
||||
type: LoadBalancer
|
||||
```
|
||||
|
||||
#### Secrets
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: quoter-secrets
|
||||
type: Opaque
|
||||
data:
|
||||
storj-access-key: <base64-encoded-key>
|
||||
storj-secret-key: <base64-encoded-secret>
|
||||
aws-access-key: <base64-encoded-key>
|
||||
aws-secret-key: <base64-encoded-secret>
|
||||
```
|
||||
|
||||
### 3. Systemd (Linux)
|
||||
|
||||
#### Создание сервиса
|
||||
|
||||
Создайте `/etc/systemd/system/quoter.service`:
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=Quoter File Service
|
||||
After=network.target redis.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=quoter
|
||||
Group=quoter
|
||||
WorkingDirectory=/opt/quoter
|
||||
Environment=REDIS_URL=redis://localhost:6379
|
||||
Environment=CORE_URL=https://api.example.com/graphql
|
||||
Environment=STORJ_ACCESS_KEY=your-key
|
||||
Environment=STORJ_SECRET_KEY=your-secret
|
||||
Environment=AWS_ACCESS_KEY=your-aws-key
|
||||
Environment=AWS_SECRET_KEY=your-aws-secret
|
||||
Environment=RUST_LOG=info
|
||||
ExecStart=/opt/quoter/quoter
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
#### Управление сервисом
|
||||
|
||||
```bash
|
||||
# Создание пользователя
|
||||
sudo useradd -r -s /bin/false quoter
|
||||
|
||||
# Копирование бинарного файла
|
||||
sudo cp target/release/quoter /opt/quoter/
|
||||
sudo chown quoter:quoter /opt/quoter/quoter
|
||||
|
||||
# Включение и запуск сервиса
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable quoter
|
||||
sudo systemctl start quoter
|
||||
|
||||
# Проверка статуса
|
||||
sudo systemctl status quoter
|
||||
```
|
||||
|
||||
## Мониторинг и логирование
|
||||
|
||||
### Prometheus метрики
|
||||
|
||||
Добавьте в `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
prometheus = "0.13"
|
||||
actix-web-prom = "0.6"
|
||||
```
|
||||
|
||||
### Grafana дашборд
|
||||
|
||||
Создайте дашборд для мониторинга:
|
||||
|
||||
- Количество запросов в секунду
|
||||
- Время ответа API
|
||||
- Использование памяти и CPU
|
||||
- Ошибки по типам
|
||||
- Использование квот
|
||||
|
||||
### Логирование
|
||||
|
||||
#### Структурированные логи
|
||||
|
||||
```bash
|
||||
# JSON формат для ELK stack
|
||||
RUST_LOG=info cargo run | jq .
|
||||
```
|
||||
|
||||
#### Ротация логов
|
||||
|
||||
Настройте logrotate:
|
||||
|
||||
```
|
||||
/var/log/quoter/*.log {
|
||||
daily
|
||||
missingok
|
||||
rotate 52
|
||||
compress
|
||||
delaycompress
|
||||
notifempty
|
||||
create 644 quoter quoter
|
||||
postrotate
|
||||
systemctl reload quoter
|
||||
endscript
|
||||
}
|
||||
```
|
||||
|
||||
## Масштабирование
|
||||
|
||||
### Горизонтальное масштабирование
|
||||
|
||||
1. **Load Balancer**: Настройте nginx или HAProxy
|
||||
2. **Redis Cluster**: Для высоких нагрузок
|
||||
3. **S3 CDN**: Для статических файлов
|
||||
|
||||
### Вертикальное масштабирование
|
||||
|
||||
- Увеличьте ресурсы контейнера/сервера
|
||||
- Настройте пул соединений Redis
|
||||
- Оптимизируйте размер изображений
|
||||
|
||||
## Безопасность
|
||||
|
||||
### Сетевая безопасность
|
||||
|
||||
- Используйте HTTPS в продакшене
|
||||
- Настройте firewall
|
||||
- Ограничьте доступ к Redis
|
||||
|
||||
### Секреты
|
||||
|
||||
- Используйте Kubernetes Secrets или Docker Secrets
|
||||
- Не храните секреты в коде
|
||||
- Ротация ключей доступа
|
||||
|
||||
### Аудит
|
||||
|
||||
- Логируйте все операции с файлами
|
||||
- Отслеживайте использование квот
|
||||
- Мониторьте подозрительную активность
|
||||
422
docs/development.md
Normal file
422
docs/development.md
Normal file
@@ -0,0 +1,422 @@
|
||||
# Разработка
|
||||
|
||||
## Настройка среды разработки
|
||||
|
||||
### Требования
|
||||
|
||||
- **Rust**: 1.70 или выше
|
||||
- **Redis**: 6.0 или выше (локально или Docker)
|
||||
- **Git**: для работы с репозиторием
|
||||
- **IDE**: VS Code, IntelliJ IDEA или другой редактор с поддержкой Rust
|
||||
|
||||
### Установка Rust
|
||||
|
||||
```bash
|
||||
# Установка Rust через rustup
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
|
||||
# Перезагрузка shell
|
||||
source ~/.bashrc
|
||||
|
||||
# Проверка установки
|
||||
rustc --version
|
||||
cargo --version
|
||||
```
|
||||
|
||||
### Клонирование репозитория
|
||||
|
||||
```bash
|
||||
git clone https://github.com/your-org/quoter.git
|
||||
cd quoter
|
||||
```
|
||||
|
||||
### Установка зависимостей
|
||||
|
||||
```bash
|
||||
# Сборка проекта
|
||||
cargo build
|
||||
|
||||
# Установка дополнительных инструментов
|
||||
cargo install cargo-watch # для автоматической пересборки
|
||||
cargo install cargo-audit # для проверки безопасности
|
||||
cargo install cargo-tarpaulin # для покрытия кода тестами
|
||||
```
|
||||
|
||||
## Структура проекта
|
||||
|
||||
```
|
||||
quoter/
|
||||
├── src/
|
||||
│ ├── main.rs # Точка входа приложения
|
||||
│ ├── app_state.rs # Состояние приложения и подключения
|
||||
│ ├── auth.rs # Аутентификация и авторизация
|
||||
│ ├── core.rs # Интеграция с API ядра
|
||||
│ ├── lookup.rs # Поиск и определение MIME-типов
|
||||
│ ├── overlay.rs # Генерация оверлеев для изображений
|
||||
│ ├── s3_utils.rs # Утилиты для работы с S3
|
||||
│ ├── thumbnail.rs # Создание миниатюр
|
||||
│ └── handlers/ # HTTP обработчики
|
||||
│ ├── mod.rs # Модуль обработчиков
|
||||
│ ├── upload.rs # Загрузка файлов
|
||||
│ ├── proxy.rs # Получение файлов
|
||||
│ ├── quota.rs # Управление квотами
|
||||
│ └── serve_file.rs # Обслуживание файлов
|
||||
├── docs/ # Документация
|
||||
├── tests/ # Интеграционные тесты
|
||||
├── Cargo.toml # Зависимости и конфигурация
|
||||
├── Cargo.lock # Фиксированные версии зависимостей
|
||||
├── Dockerfile # Docker образ
|
||||
└── README.md # Основная документация
|
||||
```
|
||||
|
||||
## Локальная разработка
|
||||
|
||||
### Настройка переменных окружения
|
||||
|
||||
Создайте файл `.env` в корне проекта:
|
||||
|
||||
```bash
|
||||
# Redis (локально или Docker)
|
||||
REDIS_URL=redis://localhost:6379
|
||||
|
||||
# Core API (замените на ваш endpoint)
|
||||
CORE_URL=https://api.example.com/graphql
|
||||
|
||||
# Storj S3 (тестовые ключи)
|
||||
STORJ_ACCESS_KEY=your-test-key
|
||||
STORJ_SECRET_KEY=your-test-secret
|
||||
STORJ_BUCKET_NAME=test-bucket
|
||||
|
||||
# AWS S3 (тестовые ключи)
|
||||
AWS_ACCESS_KEY=your-test-aws-key
|
||||
AWS_SECRET_KEY=your-test-aws-secret
|
||||
|
||||
# Server
|
||||
PORT=8080
|
||||
RUST_LOG=debug
|
||||
```
|
||||
|
||||
### Запуск Redis
|
||||
|
||||
#### Локально
|
||||
```bash
|
||||
# Ubuntu/Debian
|
||||
sudo apt-get install redis-server
|
||||
sudo systemctl start redis-server
|
||||
|
||||
# macOS
|
||||
brew install redis
|
||||
brew services start redis
|
||||
|
||||
# Проверка
|
||||
redis-cli ping
|
||||
```
|
||||
|
||||
#### Docker
|
||||
```bash
|
||||
docker run -d \
|
||||
--name redis-dev \
|
||||
-p 6379:6379 \
|
||||
redis:7-alpine
|
||||
```
|
||||
|
||||
### Запуск приложения
|
||||
|
||||
```bash
|
||||
# Обычный запуск
|
||||
cargo run
|
||||
|
||||
# С автоматической пересборкой
|
||||
cargo watch -x run
|
||||
|
||||
# В режиме отладки
|
||||
RUST_LOG=debug cargo run
|
||||
|
||||
# С профилированием
|
||||
cargo run --release
|
||||
```
|
||||
|
||||
### Проверка работоспособности
|
||||
|
||||
```bash
|
||||
# Проверка сервера
|
||||
curl http://localhost:8080/
|
||||
|
||||
# Проверка загрузки файла (требует токен)
|
||||
curl -X POST http://localhost:8080/ \
|
||||
-H "Authorization: Bearer your-token" \
|
||||
-F "file=@test-image.jpg"
|
||||
```
|
||||
|
||||
## Тестирование
|
||||
|
||||
### Unit тесты
|
||||
|
||||
```bash
|
||||
# Запуск всех тестов
|
||||
cargo test
|
||||
|
||||
# Запуск тестов с выводом
|
||||
cargo test -- --nocapture
|
||||
|
||||
# Запуск конкретного теста
|
||||
cargo test test_upload_file
|
||||
|
||||
# Запуск тестов в параллельном режиме
|
||||
cargo test -- --test-threads=4
|
||||
```
|
||||
|
||||
### Интеграционные тесты
|
||||
|
||||
Создайте файл `tests/integration_test.rs`:
|
||||
|
||||
```rust
|
||||
use actix_web::{test, web, App};
|
||||
use quoter::app_state::AppState;
|
||||
|
||||
#[actix_web::test]
|
||||
async fn test_upload_endpoint() {
|
||||
let app_state = AppState::new().await;
|
||||
let app = test::init_service(
|
||||
App::new()
|
||||
.app_data(web::Data::new(app_state))
|
||||
.route("/", web::post().to(upload_handler))
|
||||
).await;
|
||||
|
||||
let req = test::TestRequest::post()
|
||||
.uri("/")
|
||||
.insert_header(("Authorization", "Bearer test-token"))
|
||||
.set_form(("file", "test-data"))
|
||||
.to_request();
|
||||
|
||||
let resp = test::call_service(&app, req).await;
|
||||
assert!(resp.status().is_success());
|
||||
}
|
||||
```
|
||||
|
||||
### Тестирование производительности
|
||||
|
||||
```bash
|
||||
# Бенчмарки (если настроены)
|
||||
cargo bench
|
||||
|
||||
# Профилирование с flamegraph
|
||||
cargo install flamegraph
|
||||
cargo flamegraph --bin quoter
|
||||
```
|
||||
|
||||
## Отладка
|
||||
|
||||
### Логирование
|
||||
|
||||
```rust
|
||||
use log::{debug, info, warn, error};
|
||||
|
||||
// В коде
|
||||
debug!("Processing file: {}", filename);
|
||||
info!("File uploaded successfully");
|
||||
warn!("User quota is getting low: {} bytes", quota);
|
||||
error!("Failed to upload file: {}", e);
|
||||
```
|
||||
|
||||
### Отладка с GDB
|
||||
|
||||
```bash
|
||||
# Компиляция с отладочной информацией
|
||||
cargo build
|
||||
|
||||
# Запуск с GDB
|
||||
gdb target/debug/quoter
|
||||
|
||||
# В GDB
|
||||
(gdb) break main
|
||||
(gdb) run
|
||||
(gdb) continue
|
||||
```
|
||||
|
||||
### Отладка с LLDB (macOS)
|
||||
|
||||
```bash
|
||||
lldb target/debug/quoter
|
||||
(lldb) breakpoint set --name main
|
||||
(lldb) run
|
||||
```
|
||||
|
||||
## Проверка кода
|
||||
|
||||
### Clippy
|
||||
|
||||
```bash
|
||||
# Проверка стиля кода
|
||||
cargo clippy
|
||||
|
||||
# Проверка с дополнительными предупреждениями
|
||||
cargo clippy -- -D warnings
|
||||
|
||||
# Автоматическое исправление
|
||||
cargo clippy --fix
|
||||
```
|
||||
|
||||
### Форматирование
|
||||
|
||||
```bash
|
||||
# Форматирование кода
|
||||
cargo fmt
|
||||
|
||||
# Проверка форматирования
|
||||
cargo fmt -- --check
|
||||
```
|
||||
|
||||
### Проверка безопасности
|
||||
|
||||
```bash
|
||||
# Аудит зависимостей
|
||||
cargo audit
|
||||
|
||||
# Проверка уязвимостей
|
||||
cargo audit --deny warnings
|
||||
```
|
||||
|
||||
## Покрытие кода
|
||||
|
||||
### Tarpaulin
|
||||
|
||||
```bash
|
||||
# Установка
|
||||
cargo install cargo-tarpaulin
|
||||
|
||||
# Запуск
|
||||
cargo tarpaulin
|
||||
|
||||
# С HTML отчетом
|
||||
cargo tarpaulin --out Html
|
||||
```
|
||||
|
||||
### grcov
|
||||
|
||||
```bash
|
||||
# Установка
|
||||
cargo install grcov
|
||||
|
||||
# Настройка переменных
|
||||
export CARGO_INCREMENTAL=0
|
||||
export RUSTFLAGS="-Zprofile -Ccodegen-units=1 -Cinline-threshold=0 -Clink-dead-code -Coverflow-checks=off -Cpanic=abort -Zpanic_abort_tests"
|
||||
export RUSTDOCFLAGS="-Zprofile -Ccodegen-units=1 -Cinline-threshold=0 -Clink-dead-code -Coverflow-checks=off -Cpanic=abort -Zpanic_abort_tests"
|
||||
|
||||
# Запуск тестов
|
||||
cargo test
|
||||
|
||||
# Генерация отчета
|
||||
grcov . -s . --binary-path ./target/debug/ -t html --branch --ignore-not-existing -o ./coverage/
|
||||
```
|
||||
|
||||
## Git workflow
|
||||
|
||||
### Создание feature branch
|
||||
|
||||
```bash
|
||||
# Создание новой ветки
|
||||
git checkout -b feature/new-feature
|
||||
|
||||
# Внесение изменений
|
||||
# ...
|
||||
|
||||
# Коммит изменений
|
||||
git add .
|
||||
git commit -m "feat: add new feature"
|
||||
|
||||
# Push в репозиторий
|
||||
git push origin feature/new-feature
|
||||
```
|
||||
|
||||
### Commit conventions
|
||||
|
||||
Используйте [Conventional Commits](https://www.conventionalcommits.org/):
|
||||
|
||||
- `feat:` - новая функциональность
|
||||
- `fix:` - исправление багов
|
||||
- `docs:` - изменения в документации
|
||||
- `style:` - форматирование кода
|
||||
- `refactor:` - рефакторинг кода
|
||||
- `test:` - добавление тестов
|
||||
- `chore:` - обновление зависимостей, конфигурации
|
||||
|
||||
### Pull Request
|
||||
|
||||
1. Создайте Pull Request в GitHub/GitLab
|
||||
2. Добавьте описание изменений
|
||||
3. Укажите связанные issues
|
||||
4. Дождитесь code review
|
||||
5. Исправьте замечания если есть
|
||||
6. Получите approval и merge
|
||||
|
||||
## Полезные команды
|
||||
|
||||
### Cargo
|
||||
|
||||
```bash
|
||||
# Обновление зависимостей
|
||||
cargo update
|
||||
|
||||
# Очистка сборки
|
||||
cargo clean
|
||||
|
||||
# Проверка зависимостей
|
||||
cargo tree
|
||||
|
||||
# Документация
|
||||
cargo doc --open
|
||||
|
||||
# Проверка типов без компиляции
|
||||
cargo check
|
||||
```
|
||||
|
||||
### Отладка
|
||||
|
||||
```bash
|
||||
# Просмотр логов в реальном времени
|
||||
tail -f logs/quoter.log
|
||||
|
||||
# Мониторинг ресурсов
|
||||
htop
|
||||
iotop
|
||||
|
||||
# Сетевые соединения
|
||||
netstat -tulpn | grep 8080
|
||||
```
|
||||
|
||||
### Docker
|
||||
|
||||
```bash
|
||||
# Сборка для разработки
|
||||
docker build -t quoter:dev .
|
||||
|
||||
# Запуск с volume для hot reload
|
||||
docker run -v $(pwd):/app -p 8080:8080 quoter:dev
|
||||
|
||||
# Просмотр логов контейнера
|
||||
docker logs -f quoter-container
|
||||
```
|
||||
|
||||
## Рекомендации
|
||||
|
||||
### Производительность
|
||||
|
||||
1. Используйте `cargo build --release` для production
|
||||
2. Настройте профилирование для критических участков
|
||||
3. Мониторьте использование памяти и CPU
|
||||
4. Оптимизируйте размер изображений
|
||||
|
||||
### Безопасность
|
||||
|
||||
1. Регулярно обновляйте зависимости
|
||||
2. Используйте `cargo audit` для проверки уязвимостей
|
||||
3. Не храните секреты в коде
|
||||
4. Валидируйте все входные данные
|
||||
|
||||
### Качество кода
|
||||
|
||||
1. Пишите тесты для новой функциональности
|
||||
2. Используйте `cargo clippy` для проверки стиля
|
||||
3. Документируйте публичные API
|
||||
4. Следуйте принципам SOLID
|
||||
25
docs/how-it-works.md
Normal file
25
docs/how-it-works.md
Normal file
@@ -0,0 +1,25 @@
|
||||
### Как это работает
|
||||
|
||||
1. **Аутентификация**:
|
||||
- Клиент отправляет файл на сервер с заголовком `Authorization`, содержащим токен. Сервер проверяет наличие и валидность токена через API ядра, определяя пользователя.
|
||||
|
||||
2. **Загрузка файлов**:
|
||||
- Сервер обрабатывает все загружаемые файлы. Если файл является изображением, создается его миниатюра. И миниатюра, и оригинальное изображение загружаются в S3. Для остальных файлов выполняется простая загрузка в S3 без создания миниатюр.
|
||||
|
||||
3. **Создание миниатюр**:
|
||||
- Для всех загружаемых изображений сервер автоматически создает миниатюры различных размеров (10, 40, 110, 300, 600, 800, 1400 пикселей по ширине). Миниатюры сохраняются как отдельные файлы в том же S3 bucket, что и оригинальные изображения.
|
||||
|
||||
4. **Определение MIME-типа и расширения файла**:
|
||||
- MIME-тип и расширение файла определяются автоматически на основе имени файла и его содержимого с использованием библиотеки `mime_guess`.
|
||||
|
||||
5. **Загрузка файлов в S3**:
|
||||
- Все файлы, включая миниатюры и оригиналы изображений, загружаются в указанный S3 bucket. Сформированные URL-адреса файлов возвращаются клиенту.
|
||||
|
||||
6. **Управление квотами**:
|
||||
- Для каждого пользователя устанавливается общая квота на загрузку данных, которая составляет 5 ГБ. Перед загрузкой каждого нового файла проверяется, не превысит ли его размер текущую квоту пользователя. Если квота будет превышена, загрузка файла будет отклонена. После успешной загрузки файл и его размер регистрируются в Redis, и квота пользователя обновляется.
|
||||
|
||||
7. **Сохранение информации о загруженных файлах в Redis**:
|
||||
- Имя каждого загруженного файла сохраняется в Redis для отслеживания загруженных пользователем файлов. Это позволяет учитывать квоты и управлять пространством, занимаемым файлами.
|
||||
|
||||
8. **Оверлей для shout**:
|
||||
- При загрузке файла, если он является изображением, и в запросе присутствует параметр `s=<shout_id>`, то к файлу будет добавлен оверлей с данными shout.
|
||||
341
docs/monitoring.md
Normal file
341
docs/monitoring.md
Normal file
@@ -0,0 +1,341 @@
|
||||
# Мониторинг
|
||||
|
||||
## Обзор
|
||||
|
||||
Мониторинг Quoter включает в себя логирование, метрики производительности и отслеживание состояния системы.
|
||||
|
||||
## Логирование
|
||||
|
||||
### Уровни логирования
|
||||
|
||||
Quoter использует библиотеку `log` с различными уровнями:
|
||||
|
||||
- **error** - Критические ошибки, требующие немедленного внимания
|
||||
- **warn** - Предупреждения, которые могут указывать на проблемы
|
||||
- **info** - Информационные сообщения о нормальной работе
|
||||
- **debug** - Отладочная информация для разработчиков
|
||||
- **trace** - Максимальная детализация для глубокой отладки
|
||||
|
||||
### Настройка логирования
|
||||
|
||||
```bash
|
||||
# Только ошибки
|
||||
RUST_LOG=error cargo run
|
||||
|
||||
# Предупреждения и ошибки
|
||||
RUST_LOG=warn cargo run
|
||||
|
||||
# Информационные сообщения (рекомендуется для продакшена)
|
||||
RUST_LOG=info cargo run
|
||||
|
||||
# Отладка
|
||||
RUST_LOG=debug cargo run
|
||||
|
||||
# Максимальная детализация
|
||||
RUST_LOG=trace cargo run
|
||||
```
|
||||
|
||||
### Структура логов
|
||||
|
||||
#### Загрузка файла
|
||||
```
|
||||
[INFO] Started
|
||||
[WARN] file abc123.jpg uploaded to storj, incrementing quota by 1048576 bytes
|
||||
[WARN] New quota for user user123: 2097152 bytes
|
||||
```
|
||||
|
||||
#### Получение файла
|
||||
```
|
||||
[WARN] >>> GET image_300.jpg [START]
|
||||
[WARN] detected file extension: jpg
|
||||
[WARN] base_filename: image
|
||||
[WARN] requested width: 300
|
||||
[WARN] Found stored path in DB: production/image/image.jpg
|
||||
[WARN] File exists in Storj: production/image/image.jpg
|
||||
[WARN] Processing image file with width: 300
|
||||
[WARN] Calculated closest width: 300 for requested: 300
|
||||
[WARN] serve existed thumb file: image_300.jpg
|
||||
```
|
||||
|
||||
#### Ошибки
|
||||
```
|
||||
[ERROR] Failed to upload to Storj: image.jpg - Error: Network error
|
||||
[ERROR] Database error while getting path: image.jpg - Full error: Connection timeout
|
||||
[ERROR] unsupported file format
|
||||
```
|
||||
|
||||
## Метрики
|
||||
|
||||
### Основные метрики для мониторинга
|
||||
|
||||
#### Производительность
|
||||
- **Requests per second (RPS)** - количество запросов в секунду
|
||||
- **Response time** - время ответа API
|
||||
- **Error rate** - процент ошибок
|
||||
- **Upload success rate** - процент успешных загрузок
|
||||
|
||||
#### Ресурсы
|
||||
- **Memory usage** - использование памяти
|
||||
- **CPU usage** - использование процессора
|
||||
- **Disk I/O** - операции с диском
|
||||
- **Network I/O** - сетевой трафик
|
||||
|
||||
#### Бизнес-метрики
|
||||
- **Files uploaded** - количество загруженных файлов
|
||||
- **Quota usage** - использование квот пользователями
|
||||
- **Thumbnail generation** - количество сгенерированных миниатюр
|
||||
- **Storage usage** - использование хранилища
|
||||
|
||||
### Prometheus метрики
|
||||
|
||||
Добавьте в `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
prometheus = "0.13"
|
||||
actix-web-prom = "0.6"
|
||||
```
|
||||
|
||||
Настройте в `main.rs`:
|
||||
|
||||
```rust
|
||||
use actix_web_prom::{PrometheusMetrics, PrometheusMetricsBuilder};
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
let prometheus = PrometheusMetricsBuilder::new("quoter")
|
||||
.endpoint("/metrics")
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
HttpServer::new(move || {
|
||||
App::new()
|
||||
.wrap(prometheus.clone())
|
||||
// ... остальные настройки
|
||||
})
|
||||
.bind(addr)?
|
||||
.run()
|
||||
.await
|
||||
}
|
||||
```
|
||||
|
||||
### Кастомные метрики
|
||||
|
||||
```rust
|
||||
use prometheus::{Counter, Histogram, Registry};
|
||||
|
||||
lazy_static! {
|
||||
pub static ref UPLOAD_COUNTER: Counter = Counter::new(
|
||||
"quoter_uploads_total",
|
||||
"Total number of file uploads"
|
||||
).unwrap();
|
||||
|
||||
pub static ref UPLOAD_SIZE: Histogram = Histogram::new(
|
||||
"quoter_upload_size_bytes",
|
||||
"File upload size in bytes"
|
||||
).unwrap();
|
||||
|
||||
pub static ref QUOTA_USAGE: Histogram = Histogram::new(
|
||||
"quoter_quota_usage_bytes",
|
||||
"User quota usage in bytes"
|
||||
).unwrap();
|
||||
}
|
||||
```
|
||||
|
||||
## Алерты
|
||||
|
||||
### Критические алерты
|
||||
|
||||
- **Service down** - сервис недоступен
|
||||
- **High error rate** - высокий процент ошибок (>5%)
|
||||
- **High response time** - медленные ответы (>2s)
|
||||
- **Memory usage high** - высокое использование памяти (>80%)
|
||||
- **Redis connection failed** - потеря соединения с Redis
|
||||
|
||||
### Предупреждения
|
||||
|
||||
- **Quota usage high** - пользователи приближаются к лимиту квоты
|
||||
- **Storage usage high** - высокое использование хранилища
|
||||
- **Thumbnail generation slow** - медленная генерация миниатюр
|
||||
|
||||
### Настройка алертов в Prometheus
|
||||
|
||||
```yaml
|
||||
groups:
|
||||
- name: quoter
|
||||
rules:
|
||||
- alert: QuoterServiceDown
|
||||
expr: up{job="quoter"} == 0
|
||||
for: 1m
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: "Quoter service is down"
|
||||
|
||||
- alert: HighErrorRate
|
||||
expr: rate(http_requests_total{job="quoter",status=~"5.."}[5m]) > 0.05
|
||||
for: 2m
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "High error rate detected"
|
||||
|
||||
- alert: HighResponseTime
|
||||
expr: histogram_quantile(0.95, rate(http_request_duration_seconds_bucket{job="quoter"}[5m])) > 2
|
||||
for: 5m
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "High response time detected"
|
||||
```
|
||||
|
||||
## Дашборды
|
||||
|
||||
### Grafana дашборд
|
||||
|
||||
Создайте дашборд с панелями:
|
||||
|
||||
#### Обзор системы
|
||||
- Статус сервиса (up/down)
|
||||
- Количество запросов в секунду
|
||||
- Время ответа (p50, p95, p99)
|
||||
- Процент ошибок
|
||||
|
||||
#### Загрузка файлов
|
||||
- Количество загрузок в час/день
|
||||
- Размер загружаемых файлов
|
||||
- Успешность загрузок
|
||||
- Использование квот
|
||||
|
||||
#### Ресурсы
|
||||
- Использование CPU и памяти
|
||||
- Сетевой трафик
|
||||
- Операции с диском
|
||||
- Соединения с Redis
|
||||
|
||||
#### Бизнес-метрики
|
||||
- Топ пользователей по использованию квоты
|
||||
- Популярные размеры миниатюр
|
||||
- Использование хранилища по типам файлов
|
||||
|
||||
### Пример запроса для Grafana
|
||||
|
||||
```sql
|
||||
-- Количество загрузок по часам
|
||||
SELECT
|
||||
time_bucket('1 hour', timestamp) AS time,
|
||||
COUNT(*) as uploads
|
||||
FROM quoter_uploads
|
||||
WHERE timestamp > NOW() - INTERVAL '24 hours'
|
||||
GROUP BY time
|
||||
ORDER BY time;
|
||||
```
|
||||
|
||||
## Здоровье системы
|
||||
|
||||
### Health check endpoint
|
||||
|
||||
Добавьте endpoint для проверки здоровья:
|
||||
|
||||
```rust
|
||||
async fn health_check() -> HttpResponse {
|
||||
// Проверка Redis
|
||||
let redis_ok = check_redis_connection().await;
|
||||
|
||||
// Проверка S3
|
||||
let s3_ok = check_s3_connection().await;
|
||||
|
||||
if redis_ok && s3_ok {
|
||||
HttpResponse::Ok().json(json!({
|
||||
"status": "healthy",
|
||||
"timestamp": chrono::Utc::now(),
|
||||
"services": {
|
||||
"redis": "ok",
|
||||
"s3": "ok"
|
||||
}
|
||||
}))
|
||||
} else {
|
||||
HttpResponse::ServiceUnavailable().json(json!({
|
||||
"status": "unhealthy",
|
||||
"timestamp": chrono::Utc::now(),
|
||||
"services": {
|
||||
"redis": if redis_ok { "ok" } else { "error" },
|
||||
"s3": if s3_ok { "ok" } else { "error" }
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Kubernetes liveness/readiness probes
|
||||
|
||||
```yaml
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8080
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 3
|
||||
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8080
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 3
|
||||
```
|
||||
|
||||
## Трассировка
|
||||
|
||||
### Distributed tracing
|
||||
|
||||
Для отслеживания запросов через микросервисы:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
opentelemetry = "0.20"
|
||||
tracing = "0.1"
|
||||
tracing-opentelemetry = "0.20"
|
||||
```
|
||||
|
||||
### Логирование с контекстом
|
||||
|
||||
```rust
|
||||
use tracing::{info, warn, error, instrument};
|
||||
|
||||
#[instrument(skip(state))]
|
||||
async fn upload_handler(
|
||||
req: HttpRequest,
|
||||
payload: Multipart,
|
||||
state: web::Data<AppState>,
|
||||
) -> Result<HttpResponse> {
|
||||
let user_id = get_user_id(&req).await?;
|
||||
info!(user_id = %user_id, "Starting file upload");
|
||||
|
||||
// ... логика загрузки
|
||||
|
||||
info!(user_id = %user_id, filename = %filename, "File uploaded successfully");
|
||||
Ok(response)
|
||||
}
|
||||
```
|
||||
|
||||
## Рекомендации
|
||||
|
||||
### Продакшен
|
||||
|
||||
1. **Логирование**: Используйте структурированные логи в JSON формате
|
||||
2. **Метрики**: Настройте Prometheus + Grafana
|
||||
3. **Алерты**: Настройте уведомления для критических событий
|
||||
4. **Ротация логов**: Настройте logrotate или отправку в ELK stack
|
||||
5. **Мониторинг ресурсов**: Отслеживайте CPU, память, диск, сеть
|
||||
|
||||
### Разработка
|
||||
|
||||
1. **Локальное логирование**: Используйте `RUST_LOG=debug`
|
||||
2. **Отладка**: Включите trace логи для детальной отладки
|
||||
3. **Тестирование**: Создайте тесты для проверки метрик
|
||||
4. **Документация**: Документируйте все кастомные метрики
|
||||
198
docs/testing.md
Normal file
198
docs/testing.md
Normal file
@@ -0,0 +1,198 @@
|
||||
# Тестирование
|
||||
|
||||
Этот документ описывает подход к тестированию проекта Quoter.
|
||||
|
||||
## Обзор
|
||||
|
||||
Проект использует интеграционные тесты для проверки функциональности без внешних зависимостей. Тесты написаны на Rust с использованием фреймворка Actix Web для тестирования HTTP endpoints.
|
||||
|
||||
## Запуск тестов
|
||||
|
||||
### Все тесты
|
||||
```bash
|
||||
cargo test --tests # все
|
||||
cargo test --test basic_test test_health_check # конкретный тест
|
||||
cargo test --tests -- --nocapture # Тесты с выводом
|
||||
```
|
||||
|
||||
## Описание тестов
|
||||
|
||||
### 1. Health Check (`test_health_check`)
|
||||
Проверяет работу основного endpoint `/`:
|
||||
- GET запрос возвращает статус 200 и тело "ok"
|
||||
- POST запрос возвращает статус 404 (не найден)
|
||||
|
||||
### 2. JSON Сериализация (`test_json_serialization`)
|
||||
Проверяет корректность сериализации и десериализации JSON:
|
||||
- Создание структуры с данными квоты
|
||||
- Сериализация в JSON строку
|
||||
- Десериализация обратно в структуру
|
||||
- Проверка соответствия данных
|
||||
|
||||
### 3. Multipart Form Data (`test_multipart_form_data`)
|
||||
Проверяет создание multipart form data для загрузки файлов:
|
||||
- Формирование правильного boundary
|
||||
- Добавление заголовков Content-Disposition
|
||||
- Добавление содержимого файла
|
||||
- Проверка корректности структуры
|
||||
|
||||
### 4. UUID Генерация (`test_uuid_generation`)
|
||||
Проверяет работу с UUID:
|
||||
- Генерация уникальных UUID
|
||||
- Проверка формата (36 символов с дефисами)
|
||||
- Парсинг UUID обратно
|
||||
|
||||
### 5. MIME Типы (`test_mime_type_detection`)
|
||||
Проверяет определение MIME типов по расширениям файлов:
|
||||
- Поддерживаемые форматы (jpg, png, gif, webp, mp3, wav, mp4)
|
||||
- Неподдерживаемые форматы (pdf, txt)
|
||||
- Регистронезависимость
|
||||
|
||||
### 6. Парсинг путей файлов (`test_file_path_parsing`)
|
||||
Проверяет парсинг путей файлов с размерами:
|
||||
- Извлечение базового имени, ширины и расширения
|
||||
- Обработка путей без размеров
|
||||
- Обработка путей с подчеркиваниями
|
||||
|
||||
### 7. Расчеты квот (`test_quota_calculations`)
|
||||
Проверяет логику расчета квот:
|
||||
- Различные сценарии использования квоты
|
||||
- Проверка превышения лимитов
|
||||
- Корректность математических операций
|
||||
|
||||
### 8. Форматирование размеров (`test_file_size_formatting`)
|
||||
Проверяет форматирование размеров файлов:
|
||||
- Байты, килобайты, мегабайты, гигабайты
|
||||
- Правильное округление
|
||||
- Корректные единицы измерения
|
||||
|
||||
### 9. Обработка ошибок (`test_error_handling`)
|
||||
Проверяет обработку некорректных данных:
|
||||
- Неверный JSON
|
||||
- Неполный JSON
|
||||
- Неверные UUID
|
||||
- Пустые значения
|
||||
|
||||
### 10. Производительность (`test_performance`)
|
||||
Проверяет производительность критических операций:
|
||||
- Генерация UUID (должна быть < 1μs)
|
||||
- JSON сериализация (должна быть < 100μs)
|
||||
- Вывод статистики производительности
|
||||
|
||||
## Принципы тестирования
|
||||
|
||||
### 1. Изоляция
|
||||
- Тесты не зависят от внешних сервисов (Redis, S3)
|
||||
- Каждый тест независим от других
|
||||
- Используются моки и заглушки
|
||||
|
||||
### 2. Покрытие
|
||||
- Тестируются основные функции
|
||||
- Проверяются граничные случаи
|
||||
- Тестируется обработка ошибок
|
||||
|
||||
### 3. Производительность
|
||||
- Тесты должны выполняться быстро
|
||||
- Проверяется производительность критических операций
|
||||
- Устанавливаются временные лимиты
|
||||
|
||||
### 4. Читаемость
|
||||
- Понятные названия тестов
|
||||
- Описательные сообщения об ошибках
|
||||
- Комментарии к сложной логике
|
||||
|
||||
## Добавление новых тестов
|
||||
|
||||
### 1. Создание теста
|
||||
```rust
|
||||
#[test]
|
||||
async fn test_new_feature() {
|
||||
// Подготовка
|
||||
let test_data = create_test_data();
|
||||
|
||||
// Выполнение
|
||||
let result = process_data(test_data);
|
||||
|
||||
// Проверка
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(result.unwrap(), expected_value);
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Тестирование HTTP endpoints
|
||||
```rust
|
||||
#[actix_web::test]
|
||||
async fn test_http_endpoint() {
|
||||
let app = test::init_service(
|
||||
App::new()
|
||||
.route("/test", web::get().to(test_handler))
|
||||
).await;
|
||||
|
||||
let req = test::TestRequest::get()
|
||||
.uri("/test")
|
||||
.to_request();
|
||||
|
||||
let resp = test::call_service(&app, req).await;
|
||||
assert!(resp.status().is_success());
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Тестирование производительности
|
||||
```rust
|
||||
#[test]
|
||||
async fn test_performance() {
|
||||
use std::time::Instant;
|
||||
|
||||
let start = Instant::now();
|
||||
let iterations = 10000;
|
||||
|
||||
for _ in 0..iterations {
|
||||
// Тестируемая операция
|
||||
}
|
||||
|
||||
let duration = start.elapsed();
|
||||
let avg_time = duration.as_micros() as f64 / iterations as f64;
|
||||
|
||||
assert!(avg_time < 100.0, "Operation too slow: {:.2} μs", avg_time);
|
||||
}
|
||||
```
|
||||
|
||||
## Лучшие практики
|
||||
|
||||
### 1. Именование
|
||||
- Используйте описательные имена тестов
|
||||
- Группируйте связанные тесты
|
||||
- Используйте префиксы для типов тестов
|
||||
|
||||
### 2. Организация
|
||||
- Разделяйте тесты на логические группы
|
||||
- Используйте модули для организации
|
||||
- Документируйте сложные тесты
|
||||
|
||||
### 3. Надежность
|
||||
- Избегайте хрупких тестов
|
||||
- Не полагайтесь на порядок выполнения
|
||||
- Очищайте состояние после тестов
|
||||
|
||||
### 4. Производительность
|
||||
- Минимизируйте время выполнения
|
||||
- Используйте параллельное выполнение
|
||||
- Оптимизируйте медленные тесты
|
||||
|
||||
## Отладка тестов
|
||||
|
||||
```bash
|
||||
RUST_LOG=debug cargo test --tests -- --nocapture # Вывод отладочной информации
|
||||
cargo test --tests -- --nocapture --test-threads=1 # Продолжение после ошибки
|
||||
```
|
||||
|
||||
## Покрытие кода
|
||||
|
||||
```bash
|
||||
cargo install cargo-tarpaulin # Установка cargo-tarpaulin
|
||||
cargo tarpaulin --tests # Запуск анализа покрытия
|
||||
```
|
||||
|
||||
## CI/CD интеграция
|
||||
|
||||
Тесты автоматически запускаются в CI/CD pipeline
|
||||
Reference in New Issue
Block a user