Enhance Docker and PowerShell scripts for improved functionality and maintainability
All checks were successful
Publish FaceAI Container / publish (push) Successful in 6m52s

- Updated Dockerfile to include default MySQL client for better database interaction.
- Modified entrypoint.sh to support additional workspace for legacy applications and added MySQL readiness check before startup.
- Enhanced PowerShell script for trimming MySQL dumps to include overlay dumps and improved error handling for missing race and user IDs.
- Added new image files and face encoding pickles for various projects, ensuring comprehensive data availability.
- Removed outdated face encoding pickle from PISA directory to maintain data relevance.

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
MaddoScientisto 2026-04-22 22:45:44 +02:00
commit dd7d4c865b
54 changed files with 492 additions and 144 deletions

View file

@ -7,12 +7,15 @@ const WORKSPACE_ROOT = path.resolve(ROOT_DIR, '..');
const LOG_ROOT = path.join(ROOT_DIR, 'logs');
const SEARCH_LOG_ROOT = path.join(LOG_ROOT, 'searches');
const FACEAI_BASE_URL = process.env.FACEAI_E2E_BASE_URL || 'http://127.0.0.1:3001';
const SIMULATOR_URL = process.env.FACEAI_E2E_SIMULATOR_URL || 'http://127.0.0.1:8080/Foto2.abl?id_gara=1018557&pageRow=96&pageNumber=1';
const SIMULATOR_URL = process.env.FACEAI_E2E_SIMULATOR_URL || 'http://127.0.0.1:8080/Foto2.abl?id_gara=1018547&pageRow=96&pageNumber=1';
const LEGACY_BASE_URL = process.env.FACEAI_E2E_LEGACY_BASE_URL || 'http://127.0.0.1:8080';
const LEGACY_HOME_URL = process.env.FACEAI_E2E_LEGACY_HOME_URL || `${LEGACY_BASE_URL}/index.jsp`;
const SELFIE_NAME = process.env.FACEAI_E2E_SELFIE || 'DSC_1960.JPG';
const LEGACY_LOGIN_URL = process.env.FACEAI_E2E_LEGACY_LOGIN_URL || `${LEGACY_BASE_URL}/login_clienti.html`;
const LEGACY_USERNAME = process.env.FACEAI_E2E_LEGACY_USERNAME || 'test';
const LEGACY_PASSWORD = process.env.FACEAI_E2E_LEGACY_PASSWORD || 'test1';
const SELFIE_NAME = process.env.FACEAI_E2E_SELFIE || '2026/04.APRILE/ISOLOTTO/01.FOTO/CKL_8459.JPG';
const EXPECTED_MATCH_COUNT = Number(process.env.FACEAI_E2E_EXPECTED_MATCH_COUNT || '6');
const LEGACY_RACE_ID = process.env.FACEAI_E2E_RACE_ID || '1018557';
const LEGACY_RACE_ID = process.env.FACEAI_E2E_RACE_ID || '1018547';
function quoteShellArg(value) {
if (!/[\s"]/u.test(value)) {
@ -114,17 +117,22 @@ async function waitForHttp(url, validate, timeoutMs = 3 * 60 * 1000) {
}
function getSelfiePath(fileName = SELFIE_NAME) {
const relativeSegments = fileName.split(/[\\/]+/u);
if (relativeSegments.length > 1) {
return path.join(WORKSPACE_ROOT, 'test_pkl', ...relativeSegments);
}
return path.join(WORKSPACE_ROOT, 'test_pkl', 'test_images', fileName);
}
function buildSimulatorUrl({
raceId = LEGACY_RACE_ID,
lang = 'it',
raceSlug = 'livorno',
raceName = 'Livorno',
raceSlug = 'isolotto',
raceName = 'Festa sociale UP Isolotto',
raceYear = '2026',
raceMonthFolder = '04.APRILE',
raceFolder = 'LIVORNO',
raceFolder = 'ISOLOTTO',
pageRow = '96',
pageNumber = '1'
} = {}) {
@ -139,11 +147,11 @@ function buildSimulatorUrl({
function buildHandoffUrl({
raceId = LEGACY_RACE_ID,
lang = 'it',
raceSlug = 'livorno',
raceName = 'Livorno',
raceSlug = 'isolotto',
raceName = 'Festa sociale UP Isolotto',
raceYear = '2026',
raceMonthFolder = '04.APRILE',
raceFolder = 'LIVORNO',
raceFolder = 'ISOLOTTO',
userId = '1',
displayName = `Local Test User ${userId}`,
email = `local-test-${userId}@example.invalid`,
@ -166,6 +174,86 @@ function buildHandoffUrl({
return url.toString();
}
function buildLegacyLoginFormData() {
if (!LEGACY_USERNAME || !LEGACY_PASSWORD) {
throw new Error('FACEAI_E2E_LEGACY_USERNAME and FACEAI_E2E_LEGACY_PASSWORD must be set before running authenticated local E2E checks.');
}
return {
login: LEGACY_USERNAME,
pwd: LEGACY_PASSWORD,
cmdIU: 'check',
act: '',
thePage: ''
};
}
async function performLocalLoginRequest(requestContext) {
const response = await requestContext.post(`${LEGACY_BASE_URL}/Logon.abl`, {
form: buildLegacyLoginFormData(),
failOnStatusCode: false
});
const finalUrl = response.url();
const bodyText = await response.text();
if (!response.ok()) {
throw new Error(`Local login request failed with HTTP ${response.status()} at ${finalUrl}`);
}
if (/login_clienti|Username \/ Email|Password/iu.test(bodyText) && !/user_logout|dettaglio_clienti|Il mio account/iu.test(bodyText)) {
throw new Error(`Local login request appears to have remained on the login page at ${finalUrl}`);
}
}
async function expectLocalRacePageLoaded(page) {
await page.waitForSelector('form[onsubmit="return searching()"]', { state: 'visible' });
const raceId = await page.locator('#id_gara').inputValue();
if (!/\d+/u.test(raceId)) {
throw new Error(`Expected the local race page to expose a numeric race id, got: ${raceId}`);
}
await page.waitForSelector('#faceaiLaunchButton', { state: 'visible' });
await page.waitForFunction(() => {
return document.querySelectorAll('a[data-faceai-photo-id] img.thumb').length > 0;
}, null, {
timeout: 30 * 1000
});
}
async function ensureLocalAuthenticatedRacePage(page, options = {}) {
await page.goto(LEGACY_LOGIN_URL, { waitUntil: 'domcontentloaded' });
await page.locator('#login').fill(LEGACY_USERNAME);
await page.locator('#pwd').fill(LEGACY_PASSWORD);
const submitLocator = page.locator('input[type="submit"], button[type="submit"], a.btn').filter({ hasText: /Accedi|Sign in/i }).first();
if (await submitLocator.count()) {
await Promise.all([
page.waitForNavigation({ waitUntil: 'domcontentloaded' }),
submitLocator.click()
]);
} else {
await Promise.all([
page.waitForNavigation({ waitUntil: 'domcontentloaded' }),
page.evaluate(() => {
const form = document.querySelector('form[action="Logon.abl"]');
if (!form) {
throw new Error('Local login page did not expose a Logon.abl form.');
}
const cmdIUField = form.querySelector('[name="cmdIU"]');
if (cmdIUField) {
cmdIUField.value = 'check';
}
form.submit();
})
]);
}
await page.goto(buildSimulatorUrl(options), { waitUntil: 'domcontentloaded' });
await expectLocalRacePageLoaded(page);
}
function getSearchArtifacts(searchId) {
const searchRoot = path.join(SEARCH_LOG_ROOT, searchId);
return {
@ -188,15 +276,22 @@ module.exports = {
FACEAI_BASE_URL,
LEGACY_BASE_URL,
LEGACY_HOME_URL,
LEGACY_LOGIN_URL,
LEGACY_PASSWORD,
SIMULATOR_URL,
SELFIE_NAME,
EXPECTED_MATCH_COUNT,
LEGACY_RACE_ID,
LEGACY_USERNAME,
buildHandoffUrl,
buildLegacyLoginFormData,
buildSimulatorUrl,
dockerCompose,
ensureLocalAuthenticatedRacePage,
expectLocalRacePageLoaded,
getSearchArtifacts,
getSelfiePath,
performLocalLoginRequest,
prepareHostState,
readUtf8,
runCommand,