diff --git a/.github/workflows/stg_web_svc_merge.yml b/.github/workflows/stg_web_svc_merge.yml index 2a270348fb..1a16e1cf8b 100644 --- a/.github/workflows/stg_web_svc_merge.yml +++ b/.github/workflows/stg_web_svc_merge.yml @@ -10,17 +10,15 @@ env: NODE_VERSION: "20" jobs: - web_cd: name: Deploy web service runs-on: ubuntu-latest env: - ENV_NAME : stg - CLOUDSDK_CORE_PROJECT : web-based-gtfs-validator + ENV_NAME: stg + CLOUDSDK_CORE_PROJECT: web-based-gtfs-validator steps: - - uses: actions/checkout@v4 with: # We need to download all tags so that the axion-release-plugin @@ -31,9 +29,9 @@ jobs: uses: actions/setup-java@v4 with: # We need a recent version of Java with jpackage included. - java-version: '17' + java-version: "17" # We use the zulu distribution, which is an OpenJDK distro. - distribution: 'zulu' + distribution: "zulu" # for npm - uses: actions/setup-node@v4 @@ -46,7 +44,7 @@ jobs: - uses: google-github-actions/setup-gcloud@v1 with: - version: '>= 390.0.0' + version: ">= 390.0.0" - name: run gradle tasks shell: bash diff --git a/web/client/cypress/e2e/error_messages.cy.js b/web/client/cypress/e2e/error_messages.cy.js index 14c8039ab2..77dbee3e2b 100644 --- a/web/client/cypress/e2e/error_messages.cy.js +++ b/web/client/cypress/e2e/error_messages.cy.js @@ -1,28 +1,26 @@ /// - -const url = 'https://developers.google.com/static/transit/gtfs/examples/sample-feed.zip'; +const url = + 'https://developers.google.com/static/transit/gtfs/examples/sample-feed.zip'; const jobId = '8f6be6fb-1fee-41f8-b401-b2b4b552e177-sample'; context('GTFS Validator - Confirm error messaging', () => { - it('Confirm error "Error authorizing upload"', () => { // Setup intercept aliases cy.intercept( 'POST', - `${Cypress.env("PUBLIC_CLIENT_API_ROOT")}/create-job`, + `${Cypress.env('PUBLIC_CLIENT_API_ROOT')}/create-job`, { forceNetworkError: true } - ) - .as('createJob'); + ).as('createJob'); - cy.visit('/') + cy.visit('/'); // Upload .zip file - cy.get('input#file') - .selectFile('cypress/fixtures/sample-feed.zip', { force: true }); + cy.get('input#file').selectFile('cypress/fixtures/sample-feed.zip', { + force: true, + }); // Submit - cy.get('button[type=submit]') - .click(); + cy.get('button[type=submit]').click(); // Wait for response error cy.wait('@createJob'); @@ -39,34 +37,33 @@ context('GTFS Validator - Confirm error messaging', () => { 'PUT', `https://storage.googleapis.com/stg-validator-user-uploads/${jobId}/gtfs-job.zip?X-Goog-Algorithm=GOOG4-RSA-SHA256`, { forceNetworkError: true } - ) - .as('putFile'); + ).as('putFile'); cy.intercept( 'POST', - `${Cypress.env("PUBLIC_CLIENT_API_ROOT")}/create-job`, + `${Cypress.env('PUBLIC_CLIENT_API_ROOT')}/create-job`, (req) => { req.reply({ statusCode: 200, - statusMessage: "OK", + statusMessage: 'OK', headers: { - "access-control-allow-origin": '*', - "Access-Control-Allow-Credentials": "true", + 'access-control-allow-origin': '*', + 'Access-Control-Allow-Credentials': 'true', }, body: { jobId: jobId, - url: `https://storage.googleapis.com/stg-validator-user-uploads/${jobId}/gtfs-job.zip?X-Goog-Algorithm=GOOG4-RSA-SHA256` - } + url: `https://storage.googleapis.com/stg-validator-user-uploads/${jobId}/gtfs-job.zip?X-Goog-Algorithm=GOOG4-RSA-SHA256`, + }, }); } - ) - .as('createJob'); + ).as('createJob'); - cy.visit('/') + cy.visit('/'); // Upload .zip file - cy.get('input#file') - .selectFile('cypress/fixtures/sample-feed.zip', { force: true }); + cy.get('input#file').selectFile('cypress/fixtures/sample-feed.zip', { + force: true, + }); // Submit cy.get('button[type=submit]').click(); @@ -86,32 +83,46 @@ context('GTFS Validator - Confirm error messaging', () => { // Setup intercept aliases cy.intercept( 'POST', - `${Cypress.env("PUBLIC_CLIENT_API_ROOT")}/create-job`, + `${Cypress.env('PUBLIC_CLIENT_API_ROOT')}/create-job`, (req) => { req.reply({ statusCode: 200, - statusMessage: "OK", + statusMessage: 'OK', headers: { - "access-control-allow-origin": '*', - "Access-Control-Allow-Credentials": "true", + 'access-control-allow-origin': '*', + 'Access-Control-Allow-Credentials': 'true', }, body: { jobId: jobId, - url: `https://storage.googleapis.com/stg-validator-user-uploads/${jobId}/gtfs-job.zip?X-Goog-Algorithm=GOOG4-RSA-SHA256` - } + url: `https://storage.googleapis.com/stg-validator-user-uploads/${jobId}/gtfs-job.zip?X-Goog-Algorithm=GOOG4-RSA-SHA256`, + }, }); } - ) - .as('createJob'); + ).as('createJob'); + + // Intercept HEAD request to execution_results.json - error processing error + // report failing - error processing error + cy.intercept('HEAD', './execution_result.json', (req) => { + req.reply({ + statusCode: 500, // Change the status code to represent an error + statusMessage: 'Internal Server Error', // Change the status message to represent an error + headers: { + 'access-control-allow-origin': '*', + 'Access-Control-Allow-Credentials': 'true', + }, + body: { + error: 'Error processing report.', // Add an error message to the body + }, + }); + }).as('awaitReport'); cy.intercept( 'HEAD', - `${Cypress.env("PUBLIC_CLIENT_REPORTS_ROOT")}/*/report.html`, + `${Cypress.env('PUBLIC_CLIENT_REPORTS_ROOT')}/*/report.html`, { forceNetworkError: true } - ) - .as('awaitJob'); + ).as('awaitJob'); - cy.visit('/') + cy.visit('/'); // Enter URL to .zip file cy.get('input#url').type(url); @@ -132,33 +143,35 @@ context('GTFS Validator - Confirm error messaging', () => { it('Confirm error "HTTP Error: 404"', () => { // Setup intercept aliases - cy.intercept( - 'rules.json', - (req) => { - req.reply({ - statusCode: 404, - headers: { - "access-control-allow-origin": '*', - "Access-Control-Allow-Credentials": "true", - }, - }); - } - ) - .as('getDocMarkdown'); - - cy.visit('/') + cy.intercept('rules.json', (req) => { + req.reply({ + statusCode: 404, + headers: { + 'access-control-allow-origin': '*', + 'Access-Control-Allow-Credentials': 'true', + }, + }); + }).as('getDocMarkdown'); + + cy.visit('/'); // Click "See Documentation" button cy.get('a:contains("See Documentation")').click(); - - cy.location('pathname', {timeout: 60000}).should('include', '/rules.html'); + + cy.location('pathname', { timeout: 60000 }).should( + 'include', + '/rules.html' + ); // Confirm error content cy.get('.container .markdown') .should('be.visible') .within((div) => { cy.get('h1').should('contain.text', 'HTTP Error: 404'); - cy.get('p').should('contain.text', 'There was a problem loading the rules file.'); - }) + cy.get('p').should( + 'contain.text', + 'There was a problem loading the rules file.' + ); + }); }); }); diff --git a/web/client/src/routes/+page.svelte b/web/client/src/routes/+page.svelte index 6e91ca4dd5..18ca2ecb73 100644 --- a/web/client/src/routes/+page.svelte +++ b/web/client/src/routes/+page.svelte @@ -69,6 +69,7 @@ let statusModal; $: reportUrl = `${env.PUBLIC_CLIENT_REPORTS_ROOT}/${jobId}/report.html`; + $: executionResultUrl = `${env.PUBLIC_CLIENT_REPORTS_ROOT}/${jobId}/execution_result.json`; function clearErrors() { errors = []; @@ -166,7 +167,7 @@ if (reportId) { jobId = reportId; await tick(); - const exists = await reportExists().catch(() => false); + const exists = await remoteFileExists(reportUrl).catch(() => false); updateStatus(exists ? 'ready' : 'error'); } else { // if there's no id, clear status modal @@ -270,7 +271,7 @@ do { try { - jobInProgress = !(await reportExists()); + jobInProgress = !(await remoteFileExists(executionResultUrl)); if (jobInProgress) { await sleep(2500); } @@ -278,23 +279,26 @@ jobInProgress = false; reject('Error processing report.'); } - } while (jobInProgress); + } while (jobInProgress); //TODO if report.html is not found, this will loop forever jobInProgress = false; resolve(!jobInProgress); }); } - function reportExists() { + /** + * @param {RequestInfo | URL} url + */ + function remoteFileExists(url) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.onload = () => resolve(xhr.status === 200); xhr.onerror = reject; - xhr.open('HEAD', reportUrl); + xhr.open('HEAD', url.toString()); xhr.send(); }); - } +} /** @param {string} errorText */ function addError(errorText) { @@ -343,6 +347,19 @@ }); } + if (canContinue) { + await remoteFileExists(executionResultUrl) + .then((result) => { + if (result?.status != "success") { + addError(result.error || 'Error processing report.'); + canContinue = false; + } + }).catch((error) => { + addError(error); + canContinue = false; + }); + } + // clean up if (canContinue) { updateStatus('ready');