Nettoyage du dépôt : doublons, code mort, secrets, build
Fichiers hors périmètre ou dupliqués : - suppression des 5 .md dupliqués à la racine (copies md5-identiques de docs/api/ et docs/entities/) - suppression de JANITOR_main.js / JANITOR_entities.json (application Electron sans lien avec le serveur MCP) - suppression de temp/*.json (dumps de workflows versionnés par accident) et ajout de temp/ au .gitignore - suppression de claude_desktop_config_ssh.json : mots de passe en clair et variables ORACLE_* d'une architecture abandonnée - AD_API_TEST_RESULTS.md -> docs/ad-api-validation.md (credentials du snippet remplacés par des variables d'environnement) - suppression d'IMPLEMENTATION_SUMMARY.md, doublon du précédent - queries api.php -> docs/reference-queries-api.php (renommage seul) Code mort : - suppression de src/resources/documentation.js : la resource docs:// n'a jamais été branchée dans src/index.js - suppression de src/config/constants.js : module entièrement inutilisé, requis par wms-query-service.js mais dont aucune constante n'était lue. Emporte RESOURCE_URIS.WORKFLOWS_CATEGORIES, URI déclarée jamais servie. - log-service.js : suppression de findRecentErrors, readFullLog et getLogStats, exportées mais exposées par aucun outil MCP - suppression de LOG_FILE_PATTERN (lue depuis .env, jamais appliquée : le scan filtre sur .log en dur), y compris dans .env.example - log-service.js : préfixe [Logs] sur les messages, comme les autres modules Secrets : - test-ad-api.ps1 -> scripts/test-ad-api.ps1, credentials passés en paramètres ou par WMS_USERNAME / WMS_PASSWORD au lieu d'être en dur Build et test : - @yao-pkg/pkg en devDependency, cible node22-win-x64 : npm run build échouait faute de pkg, et node20 n'a pas de binaire prébuilt (bascule sur une compilation de Node qui échoue sans toolchain MSVC) - index.js : le .env est lu à côté de l'exécutable quand le serveur est packagé. Avec un chemin statique, pkg embarquait le .env dans le snapshot, figeant les credentials dans le binaire. - scripts/test-connection.js : npm test pointait sur un fichier absent. Smoke test en lecture seule (OAuth, QueryExecute, QueryScalarExecute, API AD), par profil ou sur tous. Vérifié après nettoyage : 23 outils et 6 resources répondent au handshake MCP, npm test passe 4/4 contre le WMS. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
# AD API Testing Script
|
||||
# Tests each Application Dictionary element type endpoint
|
||||
|
||||
# Configuration - aucun credential en dur : passer par les parametres ou l'environnement.
|
||||
# Exemple : . est-ad-api.ps1 -Host 10.255.255.2 -Username mecalux -Password '***' -Tenant AD
|
||||
param(
|
||||
[string]$WmsHost = $(if ($env:WMS_HOST) { $env:WMS_HOST } else { "localhost" }),
|
||||
[string]$Username = $env:WMS_USERNAME,
|
||||
[string]$Password = $env:WMS_PASSWORD,
|
||||
[string]$Tenant = $(if ($env:WMS_TENANT) { $env:WMS_TENANT } else { "AD" }),
|
||||
[string]$Auth = $(if ($env:WMS_API_AUTH) { $env:WMS_API_AUTH } else { "Basic R05BOklFNGU3aXFoZHQ=" }),
|
||||
[string]$Application = "EasyWMS"
|
||||
)
|
||||
|
||||
if (-not $Username -or -not $Password) {
|
||||
Write-Host "Username / Password manquants. Passez -Username / -Password ou definissez WMS_USERNAME / WMS_PASSWORD." -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
$baseUrl = "https://$WmsHost"
|
||||
$tokenUrl = "$baseUrl/EasySTS/OAuth/Token"
|
||||
$adApiBase = "$baseUrl/AD/api"
|
||||
$auth = $Auth
|
||||
$username = $Username
|
||||
$password = $Password
|
||||
$tenant = $Tenant
|
||||
$application = $Application
|
||||
|
||||
# Skip SSL certificate validation (self-signed cert)
|
||||
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
|
||||
Add-Type @"
|
||||
using System.Net;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
public class TrustAllCertsPolicy : ICertificatePolicy {
|
||||
public bool CheckValidationResult(
|
||||
ServicePoint srvPoint, X509Certificate certificate,
|
||||
WebRequest request, int certificateProblem) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
"@
|
||||
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
|
||||
|
||||
Write-Host "`n=== Getting OAuth Token ===" -ForegroundColor Cyan
|
||||
|
||||
# Get OAuth token
|
||||
$tokenBody = @{
|
||||
grant_type = "password"
|
||||
tenant_code = $tenant
|
||||
username = $username
|
||||
password = $password
|
||||
}
|
||||
|
||||
try {
|
||||
$tokenResponse = Invoke-RestMethod -Uri $tokenUrl -Method Post -Headers @{
|
||||
"Authorization" = $auth
|
||||
"Content-Type" = "application/x-www-form-urlencoded"
|
||||
} -Body $tokenBody
|
||||
|
||||
$token = $tokenResponse.access_token
|
||||
Write-Host "[OK] Token obtained successfully" -ForegroundColor Green
|
||||
Write-Host " Token: $($token.Substring(0, 50))..." -ForegroundColor Gray
|
||||
}
|
||||
catch {
|
||||
Write-Host "[FAIL] Failed to get token: $($_.Exception.Message)" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Element types to test (only non-zero counts from screenshot)
|
||||
$elementTypes = @(
|
||||
@{Name="Command"; Count=1872},
|
||||
@{Name="Dialog"; Count=734},
|
||||
@{Name="Entity"; Count=331},
|
||||
@{Name="Event"; Count=1980},
|
||||
@{Name="FieldType"; Count=320},
|
||||
@{Name="Hook"; Count=60},
|
||||
@{Name="List"; Count=243},
|
||||
@{Name="Query"; Count=2016},
|
||||
@{Name="Record"; Count=337},
|
||||
@{Name="Relationship"; Count=49},
|
||||
@{Name="Report"; Count=67},
|
||||
@{Name="Resource"; Count=29374},
|
||||
@{Name="Subscription"; Count=500},
|
||||
@{Name="Validator"; Count=17},
|
||||
@{Name="ViewGroup"; Count=180},
|
||||
@{Name="View"; Count=373},
|
||||
@{Name="WorkflowAction"; Count=47},
|
||||
@{Name="Workflow"; Count=3712},
|
||||
@{Name="WritingModel"; Count=226}
|
||||
)
|
||||
|
||||
Write-Host "`n=== Testing AD API Endpoints ===" -ForegroundColor Cyan
|
||||
Write-Host "Testing $($elementTypes.Count) element types`n" -ForegroundColor Gray
|
||||
|
||||
$results = @()
|
||||
|
||||
foreach ($type in $elementTypes) {
|
||||
$typeName = $type.Name
|
||||
$expectedCount = $type.Count
|
||||
|
||||
Write-Host "Testing $typeName (expected: $expectedCount)..." -ForegroundColor Yellow -NoNewline
|
||||
|
||||
$endpoint = "$adApiBase/$typeName/GetByApplication"
|
||||
$body = @($application, $tenant, 10, 0) | ConvertTo-Json -Compress
|
||||
|
||||
try {
|
||||
$response = Invoke-RestMethod -Uri $endpoint -Method Post -Headers @{
|
||||
"Authorization" = "Bearer $token"
|
||||
"Content-Type" = "application/json"
|
||||
} -Body $body -TimeoutSec 30
|
||||
|
||||
$entities = $response.entities
|
||||
$count = if ($entities) { $entities.Count } else { 0 }
|
||||
|
||||
if ($count -gt 0) {
|
||||
Write-Host " SUCCESS ($count elements)" -ForegroundColor Green
|
||||
|
||||
# Show first element details
|
||||
$firstElement = $entities[0]
|
||||
$elementId = if ($firstElement.Id) { $firstElement.Id } else { $firstElement.id }
|
||||
$elementName = if ($firstElement.Name) { $firstElement.Name } else { $firstElement.name }
|
||||
$elementCode = if ($firstElement.Code) { $firstElement.Code } else { $firstElement.code }
|
||||
|
||||
Write-Host " First element: ID=$elementId, Name=$elementName, Code=$elementCode" -ForegroundColor Gray
|
||||
|
||||
$results += @{
|
||||
Type = $typeName
|
||||
Status = "SUCCESS"
|
||||
Count = $count
|
||||
Expected = $expectedCount
|
||||
FirstElement = @{
|
||||
Id = $elementId
|
||||
Name = $elementName
|
||||
Code = $elementCode
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
Write-Host " No entities returned" -ForegroundColor DarkYellow
|
||||
$results += @{
|
||||
Type = $typeName
|
||||
Status = "EMPTY"
|
||||
Count = 0
|
||||
Expected = $expectedCount
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Host " FAILED" -ForegroundColor Red
|
||||
Write-Host " Error: $($_.Exception.Message)" -ForegroundColor DarkRed
|
||||
$results += @{
|
||||
Type = $typeName
|
||||
Status = "FAILED"
|
||||
Error = $_.Exception.Message
|
||||
Expected = $expectedCount
|
||||
}
|
||||
}
|
||||
|
||||
Start-Sleep -Milliseconds 200
|
||||
}
|
||||
|
||||
# Summary
|
||||
Write-Host "`n=== Test Summary ===" -ForegroundColor Cyan
|
||||
$successful = ($results | Where-Object { $_.Status -eq "SUCCESS" }).Count
|
||||
$failed = ($results | Where-Object { $_.Status -eq "FAILED" }).Count
|
||||
$empty = ($results | Where-Object { $_.Status -eq "EMPTY" }).Count
|
||||
|
||||
Write-Host "Total tested: $($elementTypes.Count)" -ForegroundColor White
|
||||
Write-Host "[OK] Successful: $successful" -ForegroundColor Green
|
||||
Write-Host "[WARN] Empty: $empty" -ForegroundColor DarkYellow
|
||||
Write-Host "[FAIL] Failed: $failed" -ForegroundColor Red
|
||||
|
||||
# Detailed results
|
||||
Write-Host "`n=== Detailed Results ===" -ForegroundColor Cyan
|
||||
foreach ($result in $results) {
|
||||
$status = switch ($result.Status) {
|
||||
"SUCCESS" { "[OK]" }
|
||||
"EMPTY" { "[WARN]" }
|
||||
"FAILED" { "[FAIL]" }
|
||||
}
|
||||
|
||||
$color = switch ($result.Status) {
|
||||
"SUCCESS" { "Green" }
|
||||
"EMPTY" { "DarkYellow" }
|
||||
"FAILED" { "Red" }
|
||||
}
|
||||
|
||||
Write-Host "$status $($result.Type): " -ForegroundColor $color -NoNewline
|
||||
|
||||
if ($result.Status -eq "SUCCESS") {
|
||||
Write-Host "$($result.Count) elements (expected: $($result.Expected))" -ForegroundColor Gray
|
||||
}
|
||||
elseif ($result.Status -eq "EMPTY") {
|
||||
Write-Host "No data (expected: $($result.Expected))" -ForegroundColor Gray
|
||||
}
|
||||
else {
|
||||
Write-Host "$($result.Error)" -ForegroundColor DarkRed
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "`nTest completed.`n" -ForegroundColor Cyan
|
||||
@@ -0,0 +1,105 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Smoke test de connectivite WMS.
|
||||
*
|
||||
* npm test -> teste le profil DEFAULT_WMS_PROFILE
|
||||
* npm test -- LIMAGRAIN -> teste le profil nomme
|
||||
* npm test -- --all -> teste tous les profils declares dans WMS_PROFILES
|
||||
*
|
||||
* Verifie, pour chaque profil : chargement du profil, OAuth, QueryExecute,
|
||||
* QueryScalarExecute et l'API AD. N'ecrit rien dans le WMS.
|
||||
*/
|
||||
|
||||
const path = require('path');
|
||||
require('dotenv').config({ path: path.join(__dirname, '..', '.env') });
|
||||
|
||||
const profileManager = require('../src/config/profile-manager');
|
||||
const apiService = require('../src/services/api-service').getInstance();
|
||||
|
||||
function ok(label, detail) {
|
||||
console.log(` OK ${label}${detail ? ` - ${detail}` : ''}`);
|
||||
}
|
||||
|
||||
function ko(label, error) {
|
||||
console.log(` FAIL ${label} - ${error.message}`);
|
||||
}
|
||||
|
||||
async function step(label, fn) {
|
||||
try {
|
||||
ok(label, await fn());
|
||||
return true;
|
||||
} catch (error) {
|
||||
ko(label, error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function testProfile(name) {
|
||||
console.log(`\n=== Profil ${name} ===`);
|
||||
profileManager.switchTo(name);
|
||||
const profile = profileManager.getCurrent();
|
||||
console.log(` host=${profile.host} tenant=${profile.tenant} saas=${profile.saas}`);
|
||||
|
||||
let passed = 0;
|
||||
const total = 4;
|
||||
|
||||
if (await step('OAuth', async () => {
|
||||
await apiService.authenticate();
|
||||
return `token obtenu (age max ~${process.env.TOKEN_MAX_AGE || 1190}s)`;
|
||||
})) passed++;
|
||||
|
||||
if (await step('QueryExecute', async () => {
|
||||
const rows = await apiService.executeQuery('Context.Products.OrderBy(z => z.Id)', { take: 1 });
|
||||
return `${Array.isArray(rows) ? rows.length : 0} ligne(s)`;
|
||||
})) passed++;
|
||||
|
||||
if (await step('QueryScalarExecute', async () => {
|
||||
const count = await apiService.executeScalarQuery('Context.Products.Count()');
|
||||
return `${count} produit(s)`;
|
||||
})) passed++;
|
||||
|
||||
if (await step('AD API (Validator)', async () => {
|
||||
const res = await apiService.post('/Validator/GetByApplication',
|
||||
[profile.application, profile.tenant, 10, 0], true);
|
||||
return `${res?.entities?.length ?? 0} element(s)`;
|
||||
})) passed++;
|
||||
|
||||
console.log(` -> ${passed}/${total} tests reussis`);
|
||||
return passed === total;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
profileManager.loadProfiles();
|
||||
const available = profileManager.listProfiles();
|
||||
|
||||
if (available.length === 0) {
|
||||
console.error('Aucun profil charge. Verifiez WMS_PROFILES et <NAME>_HOST/USERNAME/PASSWORD/TENANT dans .env');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const arg = process.argv[2];
|
||||
let targets;
|
||||
if (arg === '--all') {
|
||||
targets = available;
|
||||
} else if (arg) {
|
||||
targets = [arg];
|
||||
} else {
|
||||
targets = [profileManager.getCurrentName() || available[0]];
|
||||
}
|
||||
|
||||
let allOk = true;
|
||||
for (const name of targets) {
|
||||
try {
|
||||
allOk = (await testProfile(name)) && allOk;
|
||||
} catch (error) {
|
||||
console.log(`\n=== Profil ${name} ===\n FAIL ${error.message}`);
|
||||
allOk = false;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\n${allOk ? 'Tous les profils testes sont operationnels.' : 'Au moins un test a echoue (voir ci-dessus).'}`);
|
||||
process.exit(allOk ? 0 : 1);
|
||||
}
|
||||
|
||||
main();
|
||||
Reference in New Issue
Block a user