From d04f7df899145ac41ad40196866a57d3a852e4af Mon Sep 17 00:00:00 2001 From: Jonathan Gamba Date: Mon, 11 Nov 2024 13:16:21 -0600 Subject: [PATCH] #29498 Improving postman tests --- ...ueResourceAPITests.postman_collection.json | 491 +++++++++--------- 1 file changed, 244 insertions(+), 247 deletions(-) diff --git a/dotcms-postman/src/main/resources/postman/JobQueueResourceAPITests.postman_collection.json b/dotcms-postman/src/main/resources/postman/JobQueueResourceAPITests.postman_collection.json index cbc8bc3971d6..5b1dcb1e79da 100644 --- a/dotcms-postman/src/main/resources/postman/JobQueueResourceAPITests.postman_collection.json +++ b/dotcms-postman/src/main/resources/postman/JobQueueResourceAPITests.postman_collection.json @@ -1,6 +1,6 @@ { "info": { - "_postman_id": "cc2de2d8-aecf-4063-a97c-089965ba573d", + "_postman_id": "be9c354a-6c94-4b10-be0e-bc0c1b324c24", "name": "JobQueueResource API Tests", "description": "Postman collection for testing the JobQueueResource API endpoints.", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", @@ -790,7 +790,7 @@ "", "var jobId = pm.collectionVariables.get(\"jobId\");", "console.log(\" At the time this request was sent \" + jobId);", - "pm.collectionVariables.set(\"cancelledJobId\",jobId);" + "pm.environment.set(\"cancelledJobId\",jobId);" ], "type": "text/javascript", "packages": {} @@ -1018,27 +1018,79 @@ "status" ] }, - "description": "Retrieves the status of a specific job." + "description": "Waits for the job to finish" }, "response": [] }, { - "name": "Monitor Non Existing Job", + "name": "Waiting Job to be canceled", "event": [ { "listen": "test", "script": { "exec": [ - "pm.test(\"Status code is 200\", function () {", + "const maxTimeout = 30000; // 10 seconds", + "const maxRetries = 10; // Maximum number of retry attempts", + "const startTime = parseInt(pm.environment.get(\"startTime\"));", + "const retryCount = parseInt(pm.environment.get(\"retryCount\"));", + "const elapsedTime = Date.now() - startTime;", + "", + "console.log(`Attempt ${retryCount + 1}, Elapsed time: ${elapsedTime}ms`);", + "", + "var response = pm.response.json();", + "console.log(\"Current job state:\", response.entity.state);", + " ", + "// Check if job status is \"CANCELED\"", + "if (response.entity.state === \"CANCELED\") {", + " // Clear environment variables once done", + " pm.environment.unset(\"startTime\");", + " pm.environment.unset(\"retryCount\");", + "} else if (elapsedTime < maxTimeout && retryCount < maxRetries) {", + " // Increment retry count", + " pm.environment.set(\"retryCount\", retryCount + 1);", + " ", + " setTimeout(function(){", + " console.log(\"Sleeping for 3 seconds before next request.\");", + " }, 3000);", + " postman.setNextRequest(\"Waiting Job to be canceled\");", + " console.log(`Job still processing, retrying... (${maxTimeout - elapsedTime}ms remaining)`);", + "} else {", + " // If we exceed the max timeout or max retries, fail the test", + " const timeoutReason = elapsedTime >= maxTimeout ? \"timeout\" : \"max retries\";", + " pm.environment.unset(\"startTime\");", + " pm.environment.unset(\"retryCount\");", + " pm.test(`Job state check failed due to ${timeoutReason}`, function () {", + " pm.expect.fail(`${timeoutReason} reached after ${elapsedTime}ms. Job still in processing state after ${retryCount} attempts`);", + " });", + "}", + "", + "// Add response validation", + "pm.test(\"Response is successful\", function () {", + " pm.response.to.be.success;", " pm.response.to.have.status(200);", "});", "", - "pm.test(\"Response contains job-not-found event and 404 data\", function () {", - " const responseText = pm.response.text();", - " pm.expect(responseText).to.include(\"event: job-not-found\");", - " pm.expect(responseText).to.include(\"data: 404\");", - "});", - "" + "pm.test(\"Response has the correct structure\", function () {", + " const response = pm.response.json();", + " pm.expect(response).to.have.property('entity');", + " pm.expect(response.entity).to.have.property('state');", + "});" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "if (!pm.environment.get(\"startTime\")) {", + " pm.environment.set(\"startTime\", Date.now());", + "}", + "", + "if (!pm.environment.get(\"retryCount\")) {", + " pm.environment.set(\"retryCount\", 0);", + "}" ], "type": "text/javascript", "packages": {} @@ -1047,14 +1099,9 @@ ], "request": { "method": "GET", - "header": [ - { - "key": "Accept", - "value": "text/event-stream" - } - ], + "header": [], "url": { - "raw": "{{baseUrl}}/api/v1/jobs/nonExistingJob/monitor", + "raw": "{{baseUrl}}/api/v1/jobs/{{cancelledJobId}}/status", "host": [ "{{baseUrl}}" ], @@ -1062,99 +1109,67 @@ "api", "v1", "jobs", - "nonExistingJob", - "monitor" + "{{cancelledJobId}}", + "status" ] }, - "description": "Monitors a specific job using Server-Sent Events (SSE)." + "description": "Waits for the job to finish" }, "response": [] }, { - "name": "Get Job Status Expect Cancel", + "name": "Waiting Job to fail", "event": [ { "listen": "test", "script": { "exec": [ - "// Configuration", - "const maxRetries = 5; // Number of times to retry", - "const retryDelay = 4000; // Delay between retries in milliseconds", - "", - "// Get server URL from environment variable", - "const serverURL = pm.environment.get('serverURL') || pm.collectionVariables.get('baseUrl'); // fallback to baseURL if serverURL is not defined", - "", - "// Assuming 'jobId' is set as an environment variable", - "const jobId = pm.collectionVariables.get('cancelledJobId');", - "const checkUrl = `${serverURL}/api/v1/jobs/${jobId}/status`;", - "const cancelUrl = `${serverURL}/api/v1/jobs/${jobId}/cancel`;", - "", - "// Function to check the job state", - "function checkJobState(retriesLeft) {", - "", - " console.log(\"checkURL url :: \"+checkUrl); ", - " console.log(\"cancelUrl url :: \"+cancelUrl); ", - " const token = pm.collectionVariables.get('jwt');", - "", - " pm.sendRequest({", - " url:checkUrl,", - " method:'GET',", - " header: {", - " 'Authorization': `Bearer ${token}`, // Add Bearer token in Authorization header", - " 'Content-Type': 'application/json'", - " }", - " }, ", - " function (err, response) {", - " if (err) {", - " console.error(\"Error retrieving job status:\", err);", - " return;", - " }", - " ", - " let jsonData = response.json();", - " const jobState = jsonData.entity.state;", - " console.log(jobState);", - " ", - " // Test for \"CANCELED\" state", - " if (jobState === \"CANCELED\") {", - " pm.test(\"Job has been CANCELED\", function () {", - " pm.expect(jobState).to.eql(\"CANCELED\");", - " });", - " console.log(\"Job has been successfully canceled.\");", - " } else if (retriesLeft > 0) {", - " console.log(\" retriesLeft :: \"+retriesLeft);", - " // Send a cancel POST request and retry", - " pm.sendRequest({", - " url: cancelUrl,", - " method: 'POST',", - " header: {", - " 'Authorization': `Bearer ${token}`, // Add Bearer token in Authorization header", - " 'Content-Type': 'application/json'", - " }", - " }, function (cancelErr, cancelResponse) {", - " if (cancelErr) {", - " console.error(\"Error sending cancel request:\", cancelErr);", - " } else {", - " console.log(`Cancel request sent. Status: ${cancelResponse.status}`);", - " }", - " ", - " // Wait for a delay and then check the status again", - " setTimeout(function () {", - " checkJobState(retriesLeft - 1);", - " }, retryDelay);", - " });", - " } else {", - " // If maximum retries are reached and job is still not canceled", - " pm.test(\"Job has not been CANCELED after maximum retries\", function () {", - " pm.expect(jobState).to.eql(\"CANCELED\");", - " });", - " console.warn(\"Job status is still not 'CANCELED' after maximum retries.\");", - " }", + "const maxTimeout = 30000; // 10 seconds", + "const maxRetries = 10; // Maximum number of retry attempts", + "const startTime = parseInt(pm.environment.get(\"startTime\"));", + "const retryCount = parseInt(pm.environment.get(\"retryCount\"));", + "const elapsedTime = Date.now() - startTime;", + "", + "console.log(`Attempt ${retryCount + 1}, Elapsed time: ${elapsedTime}ms`);", + "", + "var response = pm.response.json();", + "console.log(\"Current job state:\", response.entity.state);", + " ", + "// Check if job status is \"FAILED\"", + "if (response.entity.state === \"FAILED\") {", + " // Clear environment variables once done", + " pm.environment.unset(\"startTime\");", + " pm.environment.unset(\"retryCount\");", + "} else if (elapsedTime < maxTimeout && retryCount < maxRetries) {", + " // Increment retry count", + " pm.environment.set(\"retryCount\", retryCount + 1);", + " ", + " setTimeout(function(){", + " console.log(\"Sleeping for 3 seconds before next request.\");", + " }, 3000);", + " postman.setNextRequest(\"Waiting Job to fail\");", + " console.log(`Job still processing, retrying... (${maxTimeout - elapsedTime}ms remaining)`);", + "} else {", + " // If we exceed the max timeout or max retries, fail the test", + " const timeoutReason = elapsedTime >= maxTimeout ? \"timeout\" : \"max retries\";", + " pm.environment.unset(\"startTime\");", + " pm.environment.unset(\"retryCount\");", + " pm.test(`Job state check failed due to ${timeoutReason}`, function () {", + " pm.expect.fail(`${timeoutReason} reached after ${elapsedTime}ms. Job still in processing state after ${retryCount} attempts`);", " });", "}", "", - "// Initial job state check", - "checkJobState(maxRetries);", - "" + "// Add response validation", + "pm.test(\"Response is successful\", function () {", + " pm.response.to.be.success;", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Response has the correct structure\", function () {", + " const response = pm.response.json();", + " pm.expect(response).to.have.property('entity');", + " pm.expect(response.entity).to.have.property('state');", + "});" ], "type": "text/javascript", "packages": {} @@ -1164,15 +1179,13 @@ "listen": "prerequest", "script": { "exec": [ - "function sleep(milliseconds) {", - " const start = Date.now();", - " while (Date.now() - start < milliseconds) {", - " // Busy-wait loop that blocks the execution", - " }", + "if (!pm.environment.get(\"startTime\")) {", + " pm.environment.set(\"startTime\", Date.now());", "}", "", - "", - "sleep(9000);" + "if (!pm.environment.get(\"retryCount\")) {", + " pm.environment.set(\"retryCount\", 0);", + "}" ], "type": "text/javascript", "packages": {} @@ -1183,7 +1196,7 @@ "method": "GET", "header": [], "url": { - "raw": "{{baseUrl}}/api/v1/jobs/{{cancelledJobId}}/status", + "raw": "{{baseUrl}}/api/v1/jobs/{{failingJobId}}/status", "host": [ "{{baseUrl}}" ], @@ -1191,11 +1204,59 @@ "api", "v1", "jobs", - "{{cancelledJobId}}", + "{{failingJobId}}", "status" ] }, - "description": "Retrieves the status of a specific job. We expect to get one in status Canceled." + "description": "Waits for the job to finish" + }, + "response": [] + }, + { + "name": "Monitor Non Existing Job", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Response contains job-not-found event and 404 data\", function () {", + " const responseText = pm.response.text();", + " pm.expect(responseText).to.include(\"event: job-not-found\");", + " pm.expect(responseText).to.include(\"data: 404\");", + "});", + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Accept", + "value": "text/event-stream" + } + ], + "url": { + "raw": "{{baseUrl}}/api/v1/jobs/nonExistingJob/monitor", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "api", + "v1", + "jobs", + "nonExistingJob", + "monitor" + ] + }, + "description": "Monitors a specific job using Server-Sent Events (SSE)." }, "response": [] }, @@ -1207,7 +1268,7 @@ "script": { "exec": [ "// Get the expected job ID from collection variables", - "const jobId = pm.collectionVariables.get('cancelledJobId');", + "const jobId = pm.environment.get('cancelledJobId');", "", "// Parse the response JSON", "const response = pm.response.json();", @@ -1284,6 +1345,9 @@ "listen": "test", "script": { "exec": [ + "// Get the expected job ID from collection variables", + "const jobId = pm.environment.get('successJobId');", + "", "// Parse the response JSON", "const response = pm.response.json();", "", @@ -1305,7 +1369,7 @@ "", "// Validate that the job ID in the response matches the expected job ID", "pm.test(\"Job ID should match expected job ID\", function () {", - " pm.expect(response.entity.jobs[0].id).to.eql(pm.environment.get('successJobId'));", + " pm.expect(response.entity.jobs[0].id).to.eql(jobId);", "});" ], "type": "text/javascript", @@ -1359,74 +1423,32 @@ "listen": "test", "script": { "exec": [ - "// Configuration", - "const maxRetries = 5; // Maximum number of retries", - "const retryDelay = 2000; // Delay between retries in milliseconds", - "", - "// Get server URL from environment variables", - "const serverURL = pm.environment.get('serverURL') || pm.collectionVariables.get('baseUrl'); // Fallback to baseURL if serverURL is not defined", - "", - "// Define the URL for job status verification", - "const checkUrl = `${serverURL}/api/v1/jobs/failed`;", - "", - "// Function to check the status of jobs", - "function checkJobState(retriesLeft) {", - "", - " console.log(\"Checking jobs URL: \" + checkUrl);", - " const token = pm.collectionVariables.get('jwt'); ", - " // Send a GET request to fetch job statuses", - " pm.sendRequest({", - " url: checkUrl,", - " method: 'GET',", - " header: {", - " 'Authorization': `Bearer ${token}`, // Add Bearer token in Authorization header", - " 'Content-Type': 'application/json'", - " }", - " }, function (err, response) {", - " if (err) {", - " console.error(\"Error retrieving job statuses:\", err);", - " return;", - " }", - "", - " let jsonData = response.json();", - " let jobs = jsonData.entity.jobs;", - "", - " if (jobs.length > 0) {", - " // Check if all jobs have the \"FAILED\" status", - " const allFailed = jobs.every(job => job.state === \"FAILED\");", - "", - " if (allFailed) {", - " // Postman test to validate that all jobs are in the \"FAILED\" state", - " pm.test(\"All jobs are in 'FAILED' state\", function () {", - " pm.expect(allFailed).to.be.true;", - " });", - " console.log(\"All jobs are in 'FAILED' state.\");", - " } else {", - " // If any job is not in the \"FAILED\" state", - " pm.test(\"Some jobs are not in 'FAILED' state\", function () {", - " pm.expect(allFailed).to.be.true; // This will fail if not all jobs are \"FAILED\"", - " });", - " console.warn(\"Not all jobs are in 'FAILED' state.\");", - " }", - " } else if (retriesLeft > 0) {", - " // If no jobs are found and retries are left, wait and retry", - " console.log(\"No jobs available, retries left: \" + retriesLeft);", - " setTimeout(function () {", - " checkJobState(retriesLeft - 1);", - " }, retryDelay);", - " } else {", - " // If no jobs and no retries are left", - " pm.test(\"Maximum retries reached, no jobs received.\", function () {", - " pm.expect(jobs.length).to.be.greaterThan(0); // This will fail if no jobs are found", - " });", - " console.warn(\"No jobs found after maximum retries.\");", - " }", - " });", - "}", + "// Get the expected job ID from collection variables", + "const jobId = pm.environment.get('failingJobId');", "", - "// Start job status check with the maximum number of retries", - "checkJobState(maxRetries);", - "" + "// Parse the response JSON", + "const response = pm.response.json();", + "", + "// Validate that the response status is 200 OK", + "pm.test(\"Response status is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "// Validate that the response contains an \"entity.jobs\" array", + "pm.test(\"Response should contain jobs array\", function () {", + " pm.expect(response.entity).to.have.property(\"jobs\");", + " pm.expect(response.entity.jobs).to.be.an(\"array\");", + "});", + "", + "// Validate that the jobs array contains only one job", + "pm.test(\"Jobs array should contain only one job\", function () {", + " pm.expect(response.entity.jobs.length).to.eql(1);", + "});", + "", + "// Validate that the job ID in the response matches the expected job ID", + "pm.test(\"Job ID should match expected job ID\", function () {", + " pm.expect(response.entity.jobs[0].id).to.eql(jobId);", + "});" ], "type": "text/javascript", "packages": {} @@ -1465,83 +1487,50 @@ "response": [] }, { - "name": "List Jobs Expect Fail and Cancelled", + "name": "List Jobs Expect Fail, Completed and Cancelled", "event": [ { "listen": "test", "script": { "exec": [ - "// Configuration", - "const maxRetries = 5; // Maximum number of retries", - "const retryDelay = 2000; // Delay between retries in milliseconds", - "", - "// Get server URL from environment variables", - "const serverURL = pm.environment.get('serverURL') || pm.collectionVariables.get('baseUrl'); // Use baseURL as fallback if serverURL is not defined", - "", - "// Define the URL to check job statuses", - "const checkUrl = `${serverURL}/api/v1/jobs`;", - "", - "// Function to check if there are jobs in \"FAILED\" or \"CANCELED\" state", - "function checkJobState(retriesLeft) {", - "", - " console.log(\"Checking jobs URL: \" + checkUrl);", - " const token = pm.collectionVariables.get(\"jwt\");", - " // Send a GET request to get the job statuses", - " pm.sendRequest({", - " url: checkUrl,", - " method: 'GET',", - " header: {", - " 'Authorization': `Bearer ${token}`, // Add Bearer token in Authorization header", - " 'Content-Type': 'application/json'", - " }", - " }, function (err, response) {", - " if (err) {", - " console.error(\"Error retrieving job statuses:\", err);", - " return;", - " }", - "", - " let jsonData = response.json();", - " let jobs = jsonData.entity.jobs;", - "", - " if (jobs.length > 0) {", - " // Check if there are jobs with \"FAILED\" and \"CANCELED\" status", - " const hasFailed = jobs.some(job => job.state === \"FAILED\");", - " const hasCanceled = jobs.some(job => job.state === \"CANCELED\");", - "", - " // Postman test to validate that there are jobs with \"FAILED\" statuses", - " pm.test(\"There are jobs in 'FAILED' state\", function () {", - " pm.expect(hasFailed).to.be.true; ", - " });", - "", - " // Postman test to validate that there are jobs with \"CANCELED\" statuses", - " pm.test(\"There are jobs in 'CANCELED' state\", function () { ", - " pm.expect(hasCanceled).to.be.true;", - " });", - "", - " if (hasFailed && hasCanceled) {", - " console.log(\"Found jobs in 'FAILED' and 'CANCELED' state.\");", - " } else {", - " console.warn(\"Did not find jobs in both 'FAILED' and 'CANCELED' states.\");", - " }", - " } else if (retriesLeft > 0) {", - " // If no jobs are found and retries are left, wait and retry", - " console.log(\"No jobs available, retries left: \" + retriesLeft);", - " setTimeout(function () {", - " checkJobState(retriesLeft - 1);", - " }, retryDelay);", - " } else {", - " // If no jobs are found and no retries are left", - " pm.test(\"Maximum retries reached, no jobs received.\", function () {", - " pm.expect(jobs.length).to.be.greaterThan(0); // This will fail if no jobs are found", - " });", - " console.warn(\"No jobs found after reaching maximum retries.\");", - " }", - " });", - "}", + "// Parse the response JSON", + "const response = pm.response.json();", "", - "// Start checking job statuses with the maximum number of retries", - "checkJobState(maxRetries);", - "" + "// Validate that the response status is 200 OK", + "pm.test(\"Response status is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "// Validate that the response contains an \"entity.jobs\" array", + "pm.test(\"Response should contain jobs array\", function () {", + " pm.expect(response.entity).to.have.property(\"jobs\");", + " pm.expect(response.entity.jobs).to.be.an(\"array\");", + "});", + "", + "// Validate that the jobs array contains jobs", + "pm.test(\"Jobs array should have data\", function () {", + " pm.expect(response.entity.jobs.length).to.eql(3);", + "});", + "", + "// Check if there are jobs with \"FAILED\" and \"CANCELED\" status", + "const hasFailed = response.entity.jobs.some(job => job.state === \"FAILED\");", + "const hasCanceled = response.entity.jobs.some(job => job.state === \"CANCELED\");", + "const hasCompleted = response.entity.jobs.some(job => job.state === \"COMPLETED\");", + "", + "// Postman test to validate that there are jobs with \"FAILED\" statuses", + "pm.test(\"There are jobs in 'FAILED' state\", function () {", + " pm.expect(hasFailed).to.be.true; ", + "});", + "", + "// Postman test to validate that there are jobs with \"CANCELED\" statuses", + "pm.test(\"There are jobs in 'CANCELED' state\", function () { ", + " pm.expect(hasCanceled).to.be.true;", + "});", + "", + "// Postman test to validate that there are jobs with \"COMPLETED\" statuses", + "pm.test(\"There are jobs in 'COMPLETED' state\", function () { ", + " pm.expect(hasCompleted).to.be.true;", + "});" ], "type": "text/javascript", "packages": {} @@ -1693,6 +1682,14 @@ { "key": "jwt", "value": "" + }, + { + "key": "successJobId", + "value": "" + }, + { + "key": "failingJobId", + "value": "" } ] } \ No newline at end of file