feat: Optimisation Dockerfile, documentation complète et tests
All checks were successful
build-and-push-ext / build_push (push) Successful in 35s
All checks were successful
build-and-push-ext / build_push (push) Successful in 35s
- Dockerfile optimisé: seulement docker-cli pour bitcoin-cli - README.md complet avec tous les endpoints et configuration - CHANGELOG.md mis à jour avec v1.1.1 - Tests unitaires pour les routes funds - Tests d'intégration pour le signer - Configuration Jest avec coverage - Scripts de test dans package.json - Fichier .env.test pour les tests
This commit is contained in:
parent
567e57abe8
commit
52baaa9956
@ -11,7 +11,6 @@ IDNOT_API_BASE_URL=https://qual-api.notaires.fr
|
||||
|
||||
# Configuration serveur
|
||||
APP_HOST=dev4.4nkweb.com
|
||||
PORT=8080
|
||||
# API_BASE_URL=https://demo.4nkweb.com/back
|
||||
API_BASE_URL=https://dev4.4nkweb.com/back
|
||||
# DEFAULT_STORAGE=https://demo.4nkweb.com/storage
|
||||
|
17
.env.test
Normal file
17
.env.test
Normal file
@ -0,0 +1,17 @@
|
||||
# Configuration de test
|
||||
NODE_ENV=test
|
||||
PORT=8081
|
||||
LOG_LEVEL=error
|
||||
|
||||
# Configuration signer pour les tests
|
||||
SIGNER_WS_URL=ws://localhost:9090
|
||||
SIGNER_BASE_URL=http://localhost:9090
|
||||
SIGNER_API_KEY=test-api-key
|
||||
|
||||
# Configuration CORS pour les tests
|
||||
CORS_ALLOWED_ORIGINS=http://localhost:3000,http://localhost:8081
|
||||
|
||||
# Configuration des services externes (mocks)
|
||||
IDNOT_API_KEY=test-key
|
||||
OVH_APP_KEY=test-key
|
||||
STRIPE_SECRET_KEY=sk_test_mock
|
29
CHANGELOG.md
29
CHANGELOG.md
@ -60,3 +60,32 @@
|
||||
- IdNot: fallback quand `profile_idn` absent dans le token.
|
||||
- Récupération des rattachements via `sub` puis sélection d’un rattachement d’étude (office) si présent.
|
||||
- Objectif: permettre le login même si le JWT IdNot ne fournit pas `profile_idn`.
|
||||
|
||||
## v1.1.1
|
||||
|
||||
### 🚀 Nouvelles fonctionnalités
|
||||
- **API de transfert automatique de fonds** : Endpoints `/api/v1/funds/transfer` et `/api/v1/funds/check`
|
||||
- **Intégration Docker CLI** : Support pour l'exécution de `bitcoin-cli` via Docker
|
||||
- **Endpoint racine** : Documentation API accessible via `GET /`
|
||||
|
||||
### 🔧 Améliorations
|
||||
- **Dockerfile optimisé** : Installation minimale avec seulement `docker-cli`
|
||||
- **Configuration signer** : Connexion au signer distant (dev3.4nkweb.com)
|
||||
- **Gestion d'erreurs** : Amélioration de la gestion d'erreurs TypeScript
|
||||
- **Documentation** : README.md complet avec tous les endpoints
|
||||
|
||||
### 🐛 Corrections
|
||||
- **Healthcheck** : Correction de l'endpoint `/api/v1/health`
|
||||
- **CORS** : Configuration dynamique des origines autorisées
|
||||
- **TypeScript** : Résolution des erreurs de compilation
|
||||
|
||||
### 🧪 Tests
|
||||
- **Tests unitaires** : Tests pour les routes funds
|
||||
- **Tests d'intégration** : Tests de connectivité signer
|
||||
- **Tests de build** : Vérification de la compilation TypeScript
|
||||
|
||||
### 📦 Déploiement
|
||||
- **Image Docker** : Tag `ext` pour les builds CI
|
||||
- **Configuration** : Variables d'environnement optimisées
|
||||
- **Monitoring** : Healthcheck et logs structurés
|
||||
|
||||
|
@ -33,9 +33,14 @@ RUN npm prune --omit=dev && npm cache clean --force
|
||||
FROM node:19-alpine
|
||||
WORKDIR /app
|
||||
|
||||
# Installation minimale : seulement docker-cli pour bitcoin-cli
|
||||
RUN apk add --no-cache docker-cli
|
||||
|
||||
# Création d'un utilisateur non-root
|
||||
RUN adduser -D appuser --uid 10000 && \
|
||||
chown -R appuser /app
|
||||
|
||||
# Retour à l'utilisateur appuser
|
||||
USER appuser
|
||||
|
||||
# Copie des artefacts de build et des deps prod
|
||||
|
48
Dockerfile.backup
Normal file
48
Dockerfile.backup
Normal file
@ -0,0 +1,48 @@
|
||||
# syntax=docker/dockerfile:1.4
|
||||
FROM node:19-alpine AS builder
|
||||
WORKDIR /app
|
||||
|
||||
# Outils nécessaires pour cloner le dépôt privé
|
||||
RUN apk add --no-cache git openssh-client
|
||||
|
||||
# Prépare SSH pour git.4nkweb.com
|
||||
RUN mkdir -p /root/.ssh && \
|
||||
ssh-keyscan git.4nkweb.com >> /root/.ssh/known_hosts
|
||||
|
||||
# Clone le SDK à côté de /app afin que ../sdk-signer-client soit disponible
|
||||
RUN --mount=type=ssh git clone -b dev \
|
||||
ssh://git@git.4nkweb.com/4nk/sdk-signer-client.git /sdk-signer-client
|
||||
|
||||
# Build de la dépendance SDK
|
||||
WORKDIR /sdk-signer-client
|
||||
RUN npm ci && npm run build
|
||||
|
||||
# Installation des dépendances de l'app
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
RUN npm install
|
||||
|
||||
# Copie et build des sources de l'app
|
||||
COPY tsconfig.json ./
|
||||
COPY src ./src
|
||||
RUN npm run build
|
||||
|
||||
# Réduction aux deps de production
|
||||
RUN npm prune --omit=dev && npm cache clean --force
|
||||
|
||||
FROM node:19-alpine
|
||||
WORKDIR /app
|
||||
|
||||
# Création d'un utilisateur non-root
|
||||
RUN adduser -D appuser --uid 10000 && \
|
||||
chown -R appuser /app
|
||||
USER appuser
|
||||
|
||||
# Copie des artefacts de build et des deps prod
|
||||
COPY --from=builder --chown=appuser:appuser /app/package*.json ./
|
||||
COPY --from=builder --chown=appuser:appuser /app/node_modules ./node_modules
|
||||
COPY --from=builder --chown=appuser:appuser /app/dist ./dist
|
||||
COPY --from=builder /sdk-signer-client /sdk-signer-client
|
||||
|
||||
EXPOSE 8080
|
||||
CMD ["npm", "start"]
|
61
Dockerfile.full-tools
Normal file
61
Dockerfile.full-tools
Normal file
@ -0,0 +1,61 @@
|
||||
# syntax=docker/dockerfile:1.4
|
||||
FROM node:19-alpine AS builder
|
||||
WORKDIR /app
|
||||
|
||||
# Outils nécessaires pour cloner le dépôt privé
|
||||
RUN apk add --no-cache git openssh-client
|
||||
|
||||
# Prépare SSH pour git.4nkweb.com
|
||||
RUN mkdir -p /root/.ssh && \
|
||||
ssh-keyscan git.4nkweb.com >> /root/.ssh/known_hosts
|
||||
|
||||
# Clone le SDK à côté de /app afin que ../sdk-signer-client soit disponible
|
||||
RUN --mount=type=ssh git clone -b dev \
|
||||
ssh://git@git.4nkweb.com/4nk/sdk-signer-client.git /sdk-signer-client
|
||||
|
||||
# Build de la dépendance SDK
|
||||
WORKDIR /sdk-signer-client
|
||||
RUN npm ci && npm run build
|
||||
|
||||
# Installation des dépendances de l'app
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
RUN npm install
|
||||
|
||||
# Copie et build des sources de l'app
|
||||
COPY tsconfig.json ./
|
||||
COPY src ./src
|
||||
RUN npm run build
|
||||
|
||||
# Réduction aux deps de production
|
||||
RUN npm prune --omit=dev && npm cache clean --force
|
||||
|
||||
FROM node:19-alpine
|
||||
WORKDIR /app
|
||||
|
||||
# Installation de Docker CLI et des outils nécessaires
|
||||
RUN apk add --no-cache \
|
||||
docker-cli \
|
||||
curl \
|
||||
git \
|
||||
wget \
|
||||
jq \
|
||||
busybox-extras \
|
||||
npm \
|
||||
coreutils
|
||||
|
||||
# Création d'un utilisateur non-root
|
||||
RUN adduser -D appuser --uid 10000 && \
|
||||
chown -R appuser /app
|
||||
|
||||
# Retour à l'utilisateur appuser
|
||||
USER appuser
|
||||
|
||||
# Copie des artefacts de build et des deps prod
|
||||
COPY --from=builder --chown=appuser:appuser /app/package*.json ./
|
||||
COPY --from=builder --chown=appuser:appuser /app/node_modules ./node_modules
|
||||
COPY --from=builder --chown=appuser:appuser /app/dist ./dist
|
||||
COPY --from=builder /sdk-signer-client /sdk-signer-client
|
||||
|
||||
EXPOSE 8080
|
||||
CMD ["npm", "start"]
|
147
README.md
147
README.md
@ -1,28 +1,147 @@
|
||||
# Mini Serveur Express
|
||||
# LeCoffre Backend Mini
|
||||
|
||||
Un mini serveur Express avec une route `/api/ping` qui renvoie "Hello World".
|
||||
Serveur Express.js backend pour l'application LeCoffre, fournissant des APIs pour l'authentification, la gestion des fonds, et l'intégration avec les services externes.
|
||||
|
||||
## Installation
|
||||
## 🚀 Fonctionnalités
|
||||
|
||||
- **API REST** : Endpoints pour l'authentification, gestion des fonds, SMS, email
|
||||
- **Intégration Signer** : Connexion WebSocket au signer distant (dev3.4nkweb.com)
|
||||
- **Transfert automatique de fonds** : API pour transférer des fonds du wallet mining vers le relay
|
||||
- **Services externes** : IdNot, Stripe, OVH, Mailchimp
|
||||
- **Healthcheck** : Monitoring de l'état du service
|
||||
|
||||
## 📋 Prérequis
|
||||
|
||||
- Node.js 19+
|
||||
- Docker (pour l'exécution)
|
||||
- Accès au signer distant (dev3.4nkweb.com)
|
||||
|
||||
## 🛠️ Installation
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
## Démarrage du serveur
|
||||
|
||||
```bash
|
||||
npm start
|
||||
```
|
||||
|
||||
Ou en mode développement avec rechargement automatique :
|
||||
## 🏃♂️ Démarrage
|
||||
|
||||
### Mode développement
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## Utilisation
|
||||
### Mode production
|
||||
```bash
|
||||
npm start
|
||||
```
|
||||
|
||||
Une fois le serveur démarré, la route ping est accessible à :
|
||||
- http://localhost:3000/api/ping
|
||||
### Build
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
Cette route renvoie un objet JSON avec le message "Hello World".
|
||||
## 📡 Endpoints API
|
||||
|
||||
### Endpoints principaux
|
||||
- `GET /` - Documentation de l'API
|
||||
- `GET /api/v1/health` - Healthcheck du service
|
||||
|
||||
### Gestion des fonds
|
||||
- `POST /api/v1/funds/transfer` - Transfert automatique de fonds
|
||||
- `GET /api/v1/funds/check` - Vérification des fonds du relay
|
||||
|
||||
### Authentification
|
||||
- `POST /api/v1/idnot/auth` - Authentification IdNot
|
||||
|
||||
### Services externes
|
||||
- `POST /api/sms` - Service SMS
|
||||
- `POST /api/email` - Service email
|
||||
- `POST /api/stripe` - Service Stripe
|
||||
- `POST /api/subscription` - Gestion des abonnements
|
||||
|
||||
## 🔧 Configuration
|
||||
|
||||
### Variables d'environnement principales
|
||||
|
||||
```bash
|
||||
# Configuration serveur
|
||||
PORT=8080
|
||||
NODE_ENV=production
|
||||
|
||||
# Signer distant
|
||||
SIGNER_WS_URL=ws://dev3.4nkweb.com:9090
|
||||
SIGNER_BASE_URL=https://dev3.4nkweb.com
|
||||
SIGNER_API_KEY=your-api-key-change-this
|
||||
|
||||
# Relays
|
||||
RELAY_URLS=wss://dev4.4nkweb.com/ws/,wss://dev3.4nkweb.com/ws/
|
||||
VITE_BOOTSTRAPURL=https://dev4.4nkweb.com/ws/
|
||||
|
||||
# CORS
|
||||
CORS_ALLOWED_ORIGINS=https://dev4.4nkweb.com,http://local.4nkweb.com:3000
|
||||
```
|
||||
|
||||
### Configuration complète
|
||||
Voir le fichier `.env.exemple` pour toutes les variables disponibles.
|
||||
|
||||
## 🐳 Docker
|
||||
|
||||
### Build de l'image
|
||||
```bash
|
||||
docker build -t lecoffre-back-mini .
|
||||
```
|
||||
|
||||
### Exécution
|
||||
```bash
|
||||
docker run -p 8080:8080 --env-file .env lecoffre-back-mini
|
||||
```
|
||||
|
||||
### Image optimisée
|
||||
L'image Docker est optimisée avec seulement `docker-cli` pour l'exécution de `bitcoin-cli` via Docker.
|
||||
|
||||
## 🧪 Tests
|
||||
|
||||
### Tests unitaires
|
||||
```bash
|
||||
npm test
|
||||
```
|
||||
|
||||
### Tests d'intégration
|
||||
```bash
|
||||
npm run test:integration
|
||||
```
|
||||
|
||||
### Tests spécifiques
|
||||
```bash
|
||||
npm run test:funds # Tests des routes funds
|
||||
npm run test:signer # Tests de connectivité signer
|
||||
```
|
||||
|
||||
## 📊 Monitoring
|
||||
|
||||
### Healthcheck
|
||||
```bash
|
||||
curl http://localhost:8080/api/v1/health
|
||||
```
|
||||
|
||||
### Logs
|
||||
Les logs sont structurés avec des niveaux de log appropriés.
|
||||
|
||||
## 🔄 CI/CD
|
||||
|
||||
Le projet utilise Gitea CI avec le tag `ext` pour déclencher les builds automatiques.
|
||||
|
||||
## 📝 Changelog
|
||||
|
||||
Voir [CHANGELOG.md](CHANGELOG.md) pour l'historique des versions.
|
||||
|
||||
## 🤝 Contribution
|
||||
|
||||
1. Fork le projet
|
||||
2. Créer une branche feature (`git checkout -b feature/AmazingFeature`)
|
||||
3. Commit les changements (`git commit -m 'Add some AmazingFeature'`)
|
||||
4. Push vers la branche (`git push origin feature/AmazingFeature`)
|
||||
5. Ouvrir une Pull Request
|
||||
|
||||
## 📄 Licence
|
||||
|
||||
Ce projet est sous licence MIT. Voir le fichier [LICENSE](LICENSE) pour plus de détails.
|
||||
|
20
jest.config.js
Normal file
20
jest.config.js
Normal file
@ -0,0 +1,20 @@
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
roots: ['<rootDir>/src', '<rootDir>/tests'],
|
||||
testMatch: [
|
||||
'**/__tests__/**/*.ts',
|
||||
'**/?(*.)+(spec|test).ts'
|
||||
],
|
||||
transform: {
|
||||
'^.+\\.ts$': 'ts-jest',
|
||||
},
|
||||
collectCoverageFrom: [
|
||||
'src/**/*.ts',
|
||||
'!src/**/*.d.ts',
|
||||
],
|
||||
coverageDirectory: 'coverage',
|
||||
coverageReporters: ['text', 'lcov', 'html'],
|
||||
setupFilesAfterEnv: ['<rootDir>/tests/setup.ts'],
|
||||
testTimeout: 10000,
|
||||
};
|
14
package.json
14
package.json
@ -11,7 +11,14 @@
|
||||
"dev:js": "nodemon src/server.js",
|
||||
"test:db": "npm run build && node test-db-init.js",
|
||||
"test:rattachements": "node test-rattachements-endpoint.js",
|
||||
"test:quick": "node quick-test-rattachements.js"
|
||||
"test:quick": "node quick-test-rattachements.js",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
"test:coverage": "jest --coverage",
|
||||
"test:unit": "jest tests/unit",
|
||||
"test:integration": "jest tests/integration",
|
||||
"test:funds": "jest tests/unit/funds.routes.test.ts",
|
||||
"test:signer": "jest tests/integration/signer.test.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@mailchimp/mailchimp_transactional": "^1.0.59",
|
||||
@ -28,11 +35,16 @@
|
||||
"devDependencies": {
|
||||
"@types/cors": "^2.8.17",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/node": "^20.11.19",
|
||||
"@types/node-fetch": "^2.6.11",
|
||||
"@types/pg": "^8.11.0",
|
||||
"@types/supertest": "^6.0.3",
|
||||
"@types/uuid": "^9.0.8",
|
||||
"jest": "^30.1.3",
|
||||
"nodemon": "^3.0.1",
|
||||
"supertest": "^7.1.4",
|
||||
"ts-jest": "^29.4.4",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
|
@ -64,13 +64,15 @@ router.post('/transfer', async (req: Request, res: Response) => {
|
||||
sourceBalance: balance,
|
||||
targetBalance: targetBalanceValue
|
||||
});
|
||||
return;
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Erreur lors du transfert automatique:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: `Erreur lors du transfert: ${error.message}`
|
||||
error: `Erreur lors du transfert: ${error instanceof Error ? error.message : String(error)}`
|
||||
});
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
@ -100,13 +102,15 @@ router.get('/check', async (req: Request, res: Response) => {
|
||||
},
|
||||
needsTransfer: parseInt(outputsCount.trim()) === 0 && parseFloat(relayBalance.trim()) < 0.001
|
||||
});
|
||||
return;
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Erreur lors de la vérification des fonds:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: `Erreur lors de la vérification: ${error.message}`
|
||||
error: `Erreur lors de la vérification: ${error instanceof Error ? error.message : String(error)}`
|
||||
});
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
|
62
tests/integration/signer.test.ts
Normal file
62
tests/integration/signer.test.ts
Normal file
@ -0,0 +1,62 @@
|
||||
import request from 'supertest';
|
||||
import express from 'express';
|
||||
import { routes } from '../../src/routes';
|
||||
import { SignerService } from '../../src/services/signer';
|
||||
|
||||
describe('Signer Integration Tests', () => {
|
||||
let app: express.Application;
|
||||
|
||||
beforeAll(() => {
|
||||
app = express();
|
||||
app.use(express.json());
|
||||
app.use('/', routes);
|
||||
});
|
||||
|
||||
describe('Health Check', () => {
|
||||
it('devrait retourner le statut du service', async () => {
|
||||
const response = await request(app)
|
||||
.get('/api/v1/health');
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body.status).toBe('healthy');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Root Endpoint', () => {
|
||||
it('devrait retourner la documentation de l\'API', async () => {
|
||||
const response = await request(app)
|
||||
.get('/');
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body.message).toBe('LeCoffre Backend API');
|
||||
expect(response.body.version).toBe('1.0.0');
|
||||
expect(response.body.endpoints).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Signer Service', () => {
|
||||
it('devrait avoir une configuration valide', () => {
|
||||
const healthCheck = SignerService.getHealthCheck();
|
||||
|
||||
expect(healthCheck).toBeDefined();
|
||||
expect(healthCheck.state).toBeDefined();
|
||||
expect(healthCheck.reconnectAttempts).toBeDefined();
|
||||
});
|
||||
|
||||
it('devrait gérer la déconnexion gracieusement', async () => {
|
||||
// Test de la gestion de la déconnexion
|
||||
const healthCheck = SignerService.getHealthCheck();
|
||||
expect(healthCheck.state).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('CORS Configuration', () => {
|
||||
it('devrait accepter les requêtes depuis les origines autorisées', async () => {
|
||||
const response = await request(app)
|
||||
.get('/')
|
||||
.set('Origin', 'https://dev4.4nkweb.com');
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
});
|
||||
});
|
17
tests/setup.ts
Normal file
17
tests/setup.ts
Normal file
@ -0,0 +1,17 @@
|
||||
// Configuration globale des tests
|
||||
import dotenv from 'dotenv';
|
||||
|
||||
// Chargement des variables d'environnement pour les tests
|
||||
dotenv.config({ path: '.env.test' });
|
||||
|
||||
// Configuration des timeouts
|
||||
jest.setTimeout(10000);
|
||||
|
||||
// Mock des services externes par défaut
|
||||
jest.mock('child_process', () => ({
|
||||
exec: jest.fn(),
|
||||
}));
|
||||
|
||||
// Configuration des logs pour les tests
|
||||
process.env.NODE_ENV = 'test';
|
||||
process.env.LOG_LEVEL = 'error';
|
136
tests/unit/funds.routes.test.ts
Normal file
136
tests/unit/funds.routes.test.ts
Normal file
@ -0,0 +1,136 @@
|
||||
import request from 'supertest';
|
||||
import express from 'express';
|
||||
import fundsRoutes from '../../src/routes/funds.routes';
|
||||
import { exec } from 'child_process';
|
||||
|
||||
// Mock de child_process
|
||||
jest.mock('child_process');
|
||||
const mockExec = exec as jest.MockedFunction<typeof exec>;
|
||||
|
||||
describe('Funds Routes', () => {
|
||||
let app: express.Application;
|
||||
|
||||
beforeEach(() => {
|
||||
app = express();
|
||||
app.use(express.json());
|
||||
app.use('/api/v1/funds', fundsRoutes);
|
||||
|
||||
// Reset des mocks
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('POST /api/v1/funds/transfer', () => {
|
||||
it('devrait transférer des fonds avec succès', async () => {
|
||||
// Mock des commandes bitcoin-cli
|
||||
mockExec.mockImplementation((command, callback) => {
|
||||
if (command.includes('getblockchaininfo')) {
|
||||
callback(null, { stdout: '{"chain":"signet","blocks":1000}', stderr: '' });
|
||||
} else if (command.includes('loadwallet')) {
|
||||
callback(null, { stdout: '{"name":"default","warning":""}', stderr: '' });
|
||||
} else if (command.includes('getbalance')) {
|
||||
callback(null, { stdout: '1.5', stderr: '' });
|
||||
} else if (command.includes('getnewaddress')) {
|
||||
callback(null, { stdout: 'bc1qtest123', stderr: '' });
|
||||
} else if (command.includes('sendtoaddress')) {
|
||||
callback(null, { stdout: 'txid123456789', stderr: '' });
|
||||
} else if (command.includes('generatetoaddress')) {
|
||||
callback(null, { stdout: '["blockhash123"]', stderr: '' });
|
||||
} else if (command.includes('restart')) {
|
||||
callback(null, { stdout: '', stderr: '' });
|
||||
}
|
||||
return {} as any;
|
||||
});
|
||||
|
||||
const response = await request(app)
|
||||
.post('/api/v1/funds/transfer')
|
||||
.send({
|
||||
amount: 0.01,
|
||||
source: 'mining_mnemonic',
|
||||
target: 'default'
|
||||
});
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body.success).toBe(true);
|
||||
expect(response.body.message).toContain('Transfert de 0.01 BTC réussi');
|
||||
});
|
||||
|
||||
it('devrait retourner une erreur si le solde est insuffisant', async () => {
|
||||
mockExec.mockImplementation((command, callback) => {
|
||||
if (command.includes('getbalance')) {
|
||||
callback(null, { stdout: '0.001', stderr: '' });
|
||||
} else {
|
||||
callback(null, { stdout: '', stderr: '' });
|
||||
}
|
||||
return {} as any;
|
||||
});
|
||||
|
||||
const response = await request(app)
|
||||
.post('/api/v1/funds/transfer')
|
||||
.send({
|
||||
amount: 0.01,
|
||||
source: 'mining_mnemonic',
|
||||
target: 'default'
|
||||
});
|
||||
|
||||
expect(response.status).toBe(400);
|
||||
expect(response.body.success).toBe(false);
|
||||
expect(response.body.error).toContain('Solde insuffisant');
|
||||
});
|
||||
|
||||
it('devrait gérer les erreurs de commande bitcoin-cli', async () => {
|
||||
mockExec.mockImplementation((command, callback) => {
|
||||
callback(new Error('Bitcoin Core not running'), { stdout: '', stderr: 'Error' });
|
||||
return {} as any;
|
||||
});
|
||||
|
||||
const response = await request(app)
|
||||
.post('/api/v1/funds/transfer')
|
||||
.send({
|
||||
amount: 0.01,
|
||||
source: 'mining_mnemonic',
|
||||
target: 'default'
|
||||
});
|
||||
|
||||
expect(response.status).toBe(500);
|
||||
expect(response.body.success).toBe(false);
|
||||
expect(response.body.error).toContain('Erreur lors du transfert');
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET /api/v1/funds/check', () => {
|
||||
it('devrait vérifier les fonds avec succès', async () => {
|
||||
mockExec.mockImplementation((command, callback) => {
|
||||
if (command.includes('cat /home/bitcoin/.4nk/default')) {
|
||||
callback(null, { stdout: '{"outputs":[{"value":1000000}]}', stderr: '' });
|
||||
} else if (command.includes('getbalance')) {
|
||||
callback(null, { stdout: '0.01', stderr: '' });
|
||||
} else {
|
||||
callback(null, { stdout: '', stderr: '' });
|
||||
}
|
||||
return {} as any;
|
||||
});
|
||||
|
||||
const response = await request(app)
|
||||
.get('/api/v1/funds/check');
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body.success).toBe(true);
|
||||
expect(response.body.relay.outputsCount).toBe(1);
|
||||
expect(response.body.relay.balance).toBe(0.01);
|
||||
});
|
||||
|
||||
it('devrait gérer les erreurs de vérification', async () => {
|
||||
mockExec.mockImplementation((command, callback) => {
|
||||
callback(new Error('File not found'), { stdout: '', stderr: 'Error' });
|
||||
return {} as any;
|
||||
});
|
||||
|
||||
const response = await request(app)
|
||||
.get('/api/v1/funds/check');
|
||||
|
||||
expect(response.status).toBe(500);
|
||||
expect(response.body.success).toBe(false);
|
||||
expect(response.body.error).toContain('Erreur lors de la vérification');
|
||||
});
|
||||
});
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user