From 47f1a47fa4125444b08e014a5ed83982b3d43ffa Mon Sep 17 00:00:00 2001 From: fabrizzio-dotCMS Date: Thu, 17 Oct 2024 16:09:30 -0600 Subject: [PATCH 1/3] #29480 --- .../jobs/business/error/CircuitBreaker.java | 2 +- .../dotcms/jobs/business/job/AbstractJob.java | 2 + .../rest/api/v1/job/JobQueueResource.java | 35 +- ...ueResourceAPITests.postman_collection.json | 520 +++++++++++++++--- 4 files changed, 447 insertions(+), 112 deletions(-) diff --git a/dotCMS/src/main/java/com/dotcms/jobs/business/error/CircuitBreaker.java b/dotCMS/src/main/java/com/dotcms/jobs/business/error/CircuitBreaker.java index ee6b0d3147b7..fcaa3f65f782 100644 --- a/dotCMS/src/main/java/com/dotcms/jobs/business/error/CircuitBreaker.java +++ b/dotCMS/src/main/java/com/dotcms/jobs/business/error/CircuitBreaker.java @@ -16,7 +16,7 @@ public class CircuitBreaker { // The number of failures that will cause the circuit to open static final int DEFAULT_CIRCUIT_BREAKER_FAILURE_THRESHOLD = Config.getIntProperty( - "DEFAULT_CIRCUIT_BREAKER_FAILURE_THRESHOLD", 5 + "DEFAULT_CIRCUIT_BREAKER_FAILURE_THRESHOLD", 10 ); // The time in milliseconds after which to attempt to close the circuit diff --git a/dotCMS/src/main/java/com/dotcms/jobs/business/job/AbstractJob.java b/dotCMS/src/main/java/com/dotcms/jobs/business/job/AbstractJob.java index 6af21ec986e0..590458a07f2f 100644 --- a/dotCMS/src/main/java/com/dotcms/jobs/business/job/AbstractJob.java +++ b/dotCMS/src/main/java/com/dotcms/jobs/business/job/AbstractJob.java @@ -2,6 +2,7 @@ import com.dotcms.jobs.business.processor.ProgressTracker; import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import java.time.LocalDateTime; @@ -47,6 +48,7 @@ public interface AbstractJob { Map parameters(); + @JsonIgnore Optional progressTracker(); @Default diff --git a/dotCMS/src/main/java/com/dotcms/rest/api/v1/job/JobQueueResource.java b/dotCMS/src/main/java/com/dotcms/rest/api/v1/job/JobQueueResource.java index 109807d7a1ab..fc15b93c9714 100644 --- a/dotCMS/src/main/java/com/dotcms/rest/api/v1/job/JobQueueResource.java +++ b/dotCMS/src/main/java/com/dotcms/rest/api/v1/job/JobQueueResource.java @@ -13,6 +13,7 @@ import graphql.VisibleForTesting; import java.io.IOException; import java.util.Map; +import java.util.Set; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.BeanParam; import javax.ws.rs.Consumes; @@ -68,21 +69,20 @@ public Response createJob( @GET @Path("/queues") @Produces(MediaType.APPLICATION_JSON) - public Response getQueues(@Context HttpServletRequest request) { + public ResponseEntityView> getQueues(@Context HttpServletRequest request) { new WebResource.InitBuilder(webResource) .requiredBackendUser(true) .requiredFrontendUser(false) .requestAndResponse(request, null) .rejectWhenNoUser(true) .init(); - return Response.ok(new ResponseEntityView<>(helper.getQueueNames())).build(); - + return new ResponseEntityView<>(helper.getQueueNames()); } @GET @Path("/{jobId}/status") @Produces(MediaType.APPLICATION_JSON) - public Response getJobStatus(@Context HttpServletRequest request, @PathParam("jobId") String jobId) + public ResponseEntityView getJobStatus(@Context HttpServletRequest request, @PathParam("jobId") String jobId) throws DotDataException { new WebResource.InitBuilder(webResource) @@ -93,21 +93,14 @@ public Response getJobStatus(@Context HttpServletRequest request, @PathParam("jo .init(); Job job = helper.getJob(jobId); - Map statusInfo = Map.of( - "state", job.state(), - "progress", job.progress(), - "executionNode", job.executionNode().orElse("N/A") - ); - - return Response.ok(new ResponseEntityView<>(statusInfo)).build(); - + return new ResponseEntityView<>(job); } @POST @Path("/{jobId}/cancel") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.WILDCARD) - public Response cancelJob(@Context HttpServletRequest request, @PathParam("jobId") String jobId) + public ResponseEntityView cancelJob(@Context HttpServletRequest request, @PathParam("jobId") String jobId) throws DotDataException { new WebResource.InitBuilder(webResource) .requiredBackendUser(true) @@ -116,12 +109,12 @@ public Response cancelJob(@Context HttpServletRequest request, @PathParam("jobId .rejectWhenNoUser(true) .init(); helper.cancelJob(jobId); - return Response.ok(new ResponseEntityView<>("Job cancelled successfully")).build(); + return new ResponseEntityView<>("Job cancelled successfully"); } @GET @Produces(MediaType.APPLICATION_JSON) - public Response listJobs(@Context HttpServletRequest request, + public ResponseEntityView listJobs(@Context HttpServletRequest request, @QueryParam("page") @DefaultValue("1") int page, @QueryParam("pageSize") @DefaultValue("20") int pageSize) { new WebResource.InitBuilder(webResource) @@ -131,14 +124,13 @@ public Response listJobs(@Context HttpServletRequest request, .rejectWhenNoUser(true) .init(); final JobPaginatedResult result = helper.getJobs(page, pageSize); - return Response.ok(new ResponseEntityView<>(result)).build(); - + return new ResponseEntityView<>(result); } @GET @Path("/{queueName}/active") @Produces(MediaType.APPLICATION_JSON) - public Response activeJobs(@Context HttpServletRequest request, @PathParam("queueName") String queueName, + public ResponseEntityView activeJobs(@Context HttpServletRequest request, @PathParam("queueName") String queueName, @QueryParam("page") @DefaultValue("1") int page, @QueryParam("pageSize") @DefaultValue("20") int pageSize) { new WebResource.InitBuilder(webResource) @@ -148,14 +140,13 @@ public Response activeJobs(@Context HttpServletRequest request, @PathParam("queu .rejectWhenNoUser(true) .init(); final JobPaginatedResult result = helper.getActiveJobs(queueName, page, pageSize); - return Response.ok(new ResponseEntityView<>(result)).build(); - + return new ResponseEntityView<>(result); } @GET @Path("/failed") @Produces(MediaType.APPLICATION_JSON) - public Response failedJobs(@Context HttpServletRequest request, + public ResponseEntityView failedJobs(@Context HttpServletRequest request, @QueryParam("page") @DefaultValue("1") int page, @QueryParam("pageSize") @DefaultValue("20") int pageSize) { new WebResource.InitBuilder(webResource) @@ -165,7 +156,7 @@ public Response failedJobs(@Context HttpServletRequest request, .rejectWhenNoUser(true) .init(); final JobPaginatedResult result = helper.getFailedJobs(page, pageSize); - return Response.ok(new ResponseEntityView<>(result)).build(); + return new ResponseEntityView<>(result); } 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 d1922eb66eed..66195b975b2b 100644 --- a/dotcms-postman/src/main/resources/postman/JobQueueResourceAPITests.postman_collection.json +++ b/dotcms-postman/src/main/resources/postman/JobQueueResourceAPITests.postman_collection.json @@ -1,10 +1,11 @@ { "info": { - "_postman_id": "3b8039cc-b927-45f0-a199-04c71e8d8fcf", + "_postman_id": "30a2c62f-b9b7-4828-b4bd-17b4b78be6b5", "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", - "_exporter_id": "10041132" + "_exporter_id": "10041132", + "_collection_link": "https://speeding-firefly-555540.postman.co/workspace/personal~36ad74c2-845c-4f84-8c91-495003fd59cb/collection/10041132-30a2c62f-b9b7-4828-b4bd-17b4b78be6b5?action=share&source=collection_link&creator=10041132" }, "item": [ { @@ -175,7 +176,9 @@ "var jsonData = pm.response.json();", "pm.expect(jsonData.entity).to.be.a('String');", "// Save jobId to environment variable", - "pm.environment.set(\"jobId\", jsonData.entity);" + "pm.environment.set(\"jobId\", jsonData.entity);", + "let jId = pm.environment.get(\"jobId\");", + "console.log(jId);" ], "type": "text/javascript", "packages": {} @@ -232,19 +235,120 @@ " pm.response.to.have.status(200);", "});", "", - "// Check if status info is returned", - "var jsonData = pm.response.json();", - "pm.test(\"Response has status info\", function () {", - " pm.expect(jsonData.entity).to.be.an('object');", - " pm.expect(jsonData.entity).to.have.property('state');", - " pm.expect(jsonData.entity).to.have.property('progress'); ", + "", + "// Store the response in a variable", + "let 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);", "});", "", - "pm.test(\"Job is RUNNING\", function () {", - " var object = jsonData.entity;", - " pm.expect(object.state).to.be.oneOf([\"RUNNING\", \"PENDING\"]); ", - " ", - "});" + "// Check if the 'entity' object exists", + "pm.test(\"'entity' object exists\", function () {", + " pm.expect(response).to.have.property(\"entity\");", + "});", + "", + "// Validate specific fields within `entity`", + "let entity = response.entity;", + "", + "// Check if 'completedAt' is either null or a valid date string", + "pm.test(\"'completedAt' is null or a valid date\", function () {", + " pm.expect(entity.completedAt).to.satisfy(function(val) {", + " return val === null || new Date(val).toString() !== \"Invalid Date\";", + " });", + "});", + "", + "// Check if 'createdAt' is a valid date string", + "pm.test(\"'createdAt' is a valid date string\", function () {", + " pm.expect(entity.createdAt).to.be.a(\"string\");", + " pm.expect(new Date(entity.createdAt)).to.not.equal(\"Invalid Date\");", + "});", + "", + "// Check if 'executionNode' is a UUID", + "pm.test(\"'executionNode' is a valid UUID\", function () {", + " pm.expect(entity.executionNode).to.match(/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/);", + "});", + "", + "// Check if 'id' is a UUID", + "pm.test(\"'id' is a valid UUID\", function () {", + " pm.expect(entity.id).to.match(/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/);", + "});", + "", + "// Validate the inner `parameters` object", + "let parameters = entity.parameters;", + "", + "pm.test(\"'parameters' contains expected keys with valid values\", function () {", + " pm.expect(parameters).to.have.property(\"nLines\").that.is.a(\"string\");", + " pm.expect(parameters).to.have.property(\"requestFingerPrint\").that.is.a(\"string\");", + " pm.expect(parameters.requestFingerPrint).to.have.lengthOf(44); // Base64 strings are often 44 characters for SHA-256", + " pm.expect(parameters).to.have.property(\"tempFileId\").that.is.a(\"string\");", + "});", + "", + "// Check if 'progress' is a number between 0 and 1 (e.g., a percentage)", + "pm.test(\"'progress' is a number between 0 and 1\", function () {", + " pm.expect(entity.progress).to.be.a(\"number\").within(0, 1);", + "});", + "", + "// Check if 'queueName' is a non-empty string", + "pm.test(\"'queueName' is a non-empty string\", function () {", + " pm.expect(entity.queueName).to.be.a(\"string\").that.is.not.empty;", + "});", + "", + "// Check if 'result' is either null or a valid JSON object", + "pm.test(\"'result' is null or an object\", function () {", + " pm.expect(entity.result === null || typeof entity.result === \"object\").to.be.true;", + "});", + "", + "// Check if 'retryCount' is a non-negative integer", + "pm.test(\"'retryCount' is a non-negative integer\", function () {", + " pm.expect(entity.retryCount).to.be.a(\"number\").that.is.at.least(0);", + "});", + "", + "// Check if 'startedAt' is either null or a valid date", + "pm.test(\"'startedAt' is null or a valid date\", function () {", + " pm.expect(entity.startedAt).to.satisfy(function(val) {", + " return val === null || new Date(val).toString() !== \"Invalid Date\";", + " });", + "});", + "", + "// Check if 'state' is a non-empty string", + "pm.test(\"'state' is a non-empty string\", function () {", + " pm.expect(entity.state).to.be.a(\"string\").that.is.not.empty;", + "});", + "", + "//Check status is valid ", + "pm.test(\"Job is RUNNING or PENDING\", function () { ", + " pm.expect(entity.state).to.be.oneOf([\"RUNNING\", \"PENDING\"]); ", + "});", + "", + "// Check if 'updatedAt' is a valid date string", + "pm.test(\"'updatedAt' is a valid date string\", function () {", + " pm.expect(entity.updatedAt).to.be.a(\"string\");", + " pm.expect(new Date(entity.updatedAt)).to.not.equal(\"Invalid Date\");", + "});", + "", + "// Validate other top-level objects in the response", + "pm.test(\"'errors' is an empty array\", function () {", + " pm.expect(response.errors).to.be.an(\"array\").that.is.empty;", + "});", + "", + "pm.test(\"'i18nMessagesMap' is an empty object\", function () {", + " pm.expect(response.i18nMessagesMap).to.be.an(\"object\").that.is.empty;", + "});", + "", + "pm.test(\"'messages' is an empty array\", function () {", + " pm.expect(response.messages).to.be.an(\"array\").that.is.empty;", + "});", + "", + "pm.test(\"'pagination' is null\", function () {", + " pm.expect(response.pagination).to.be.null;", + "});", + "", + "pm.test(\"'permissions' is an empty array\", function () {", + " pm.expect(response.permissions).to.be.an(\"array\").that.is.empty;", + "});", + "" ], "type": "text/javascript", "packages": {} @@ -289,11 +393,19 @@ "});", "", "var jobId = pm.environment.get(\"jobId\");", + "console.log(\" At the time this request was sent \" + jobId);", "pm.environment.set(\"cancelledJobId\",jobId);" ], "type": "text/javascript", "packages": {} } + }, + { + "listen": "prerequest", + "script": { + "packages": {}, + "type": "text/javascript" + } } ], "request": { @@ -383,23 +495,94 @@ "listen": "test", "script": { "exec": [ - "pm.test(\"Status code is 200\", function () {", + "", + "// Store the response in a variable", + "let 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);", "});", "", - "// Check if active jobs are returned", - "var jsonData = pm.response.json();", - "pm.test(\"Response has active jobs list\", function () {", - " pm.expect(jsonData.entity).to.have.property('jobs');", - " pm.expect(jsonData.entity.jobs).to.be.an('array');", + "// Check if the 'entity' object exists", + "pm.test(\"'entity' object exists\", function () {", + " pm.expect(response).to.have.property(\"entity\");", "});", "", - "var jobsArray = jsonData.entity.jobs;", + "// Validate the fields within `entity`", + "let entity = response.entity;", + "", + "// Check that 'jobs' is an array and validate its length", + "pm.test(\"'jobs' is an array with the correct length\", function () {", + " pm.expect(entity).to.have.property(\"jobs\").that.is.an(\"array\").with.lengthOf(entity.total);", + "});", + "", + "// Iterate over each job in the 'jobs' array", + "entity.jobs.forEach((job, index) => {", + " pm.test(`Job ${index + 1}: 'completedAt' is null or a valid date`, function () {", + " pm.expect(job.completedAt).to.satisfy(function(val) {", + " return val === null || new Date(val).toString() !== \"Invalid Date\";", + " });", + " });", + "", + " pm.test(`Job ${index + 1}: 'createdAt' is a valid date string`, function () {", + " pm.expect(job.createdAt).to.be.a(\"string\");", + " pm.expect(new Date(job.createdAt)).to.not.equal(\"Invalid Date\");", + " });", + "", + " pm.test(`Job ${index + 1}: 'executionNode' is a valid UUID`, function () {", + " pm.expect(job.executionNode).to.match(/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/);", + " });", + "", + " pm.test(`Job ${index + 1}: 'id' is a valid UUID`, function () {", + " pm.expect(job.id).to.match(/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/);", + " });", + "", + " // Validate the `parameters` object", + " let parameters = job.parameters;", "", - "pm.test(\"jobsArray contains objects\", function () {", - " pm.expect(jobsArray[0]).to.be.an('object');", + " pm.test(`Job ${index + 1}: 'parameters' contains expected keys with valid values`, function () {", + " pm.expect(parameters).to.have.property(\"nLines\").that.is.a(\"string\");", + " pm.expect(parameters).to.have.property(\"requestFingerPrint\").that.is.a(\"string\");", + " pm.expect(parameters.requestFingerPrint).to.have.lengthOf(44); // Typical length for SHA-256 in Base64", + " pm.expect(parameters).to.have.property(\"tempFileId\").that.is.a(\"string\");", + " });", + "", + " pm.test(`Job ${index + 1}: 'progress' is a number between 0 and 1`, function () {", + " pm.expect(job.progress).to.be.a(\"number\").within(0, 1);", + " });", + "", + " pm.test(`Job ${index + 1}: 'queueName' is a non-empty string`, function () {", + " pm.expect(job.queueName).to.be.a(\"string\").that.is.not.empty;", + " });", + "", + " pm.test(`Job ${index + 1}: 'result' is null or an object`, function () {", + " pm.expect(job.result === null || typeof job.result === \"object\").to.be.true;", + " });", + "", + " pm.test(`Job ${index + 1}: 'retryCount' is a non-negative integer`, function () {", + " pm.expect(job.retryCount).to.be.a(\"number\").that.is.at.least(0);", + " });", + "", + " pm.test(`Job ${index + 1}: 'startedAt' is null or a valid date`, function () {", + " pm.expect(job.startedAt).to.satisfy(function(val) {", + " return val === null || new Date(val).toString() !== \"Invalid Date\";", + " });", + " });", + "", + " pm.test(`Job ${index + 1}: 'state' is a non-empty string`, function () {", + " pm.expect(job.state).to.be.a(\"string\").that.is.not.empty;", + " });", + "", + " pm.test(`Job ${index + 1}: 'updatedAt' is a valid date string`, function () {", + " pm.expect(job.updatedAt).to.be.a(\"string\");", + " pm.expect(new Date(job.updatedAt)).to.not.equal(\"Invalid Date\");", + " });", "});", "", + "//Look for the last created job ", + "let jobsArray = entity.jobs;", + "", "var jobId = pm.environment.get(\"jobId\");", "pm.test(\"jobId is present in the response\", function () {", " var jobFound = jobsArray.some(function(job) {", @@ -408,6 +591,39 @@ " pm.expect(jobFound).to.be.true;", "});", "", + "// Validate pagination fields within `entity`", + "pm.test(\"'page' is a positive integer\", function () {", + " pm.expect(entity.page).to.be.a(\"number\").that.is.at.least(1);", + "});", + "", + "pm.test(\"'pageSize' is a positive integer\", function () {", + " pm.expect(entity.pageSize).to.be.a(\"number\").that.is.at.least(1);", + "});", + "", + "pm.test(\"'total' matches the length of 'jobs' array\", function () {", + " pm.expect(entity.total).to.equal(entity.jobs.length);", + "});", + "", + "// Validate other top-level objects in the response", + "pm.test(\"'errors' is an empty array\", function () {", + " pm.expect(response.errors).to.be.an(\"array\").that.is.empty;", + "});", + "", + "pm.test(\"'i18nMessagesMap' is an empty object\", function () {", + " pm.expect(response.i18nMessagesMap).to.be.an(\"object\").that.is.empty;", + "});", + "", + "pm.test(\"'messages' is an empty array\", function () {", + " pm.expect(response.messages).to.be.an(\"array\").that.is.empty;", + "});", + "", + "pm.test(\"'pagination' is null\", function () {", + " pm.expect(response.pagination).to.be.null;", + "});", + "", + "pm.test(\"'permissions' is an empty array\", function () {", + " pm.expect(response.permissions).to.be.an(\"array\").that.is.empty;", + "});", "" ], "type": "text/javascript", @@ -462,18 +678,6 @@ "pm.expect(jsonData.entity).to.be.a('String');", "// Save jobId to environment variable", "pm.environment.set(\"failingJobId\", jsonData.entity);", - "", - "function delay(milliseconds) {", - " var start = new Date().getTime();", - " var end = start;", - " while (end - start < milliseconds) {", - " end = new Date().getTime(); ", - " }", - "}", - "", - "delay(8000); ", - "", - "//And now lets wait for a show while ", "" ], "type": "text/javascript", @@ -495,11 +699,12 @@ { "key": "file", "type": "file", - "src": "resources/JobQueue/odyssey.txt" + "src": [], + "disabled": true }, { "key": "params", - "value": "{\n \"nLines\":\"1\"\n}", + "value": "{\n\n}", "type": "text" } ] @@ -575,23 +780,92 @@ "listen": "test", "script": { "exec": [ - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.have.status(200);", - "});", + "// Configuration", + "const maxRetries = 5; // Number of times to retry", + "const retryDelay = 2000; // Delay between retries in milliseconds", "", - "// Check if status info is returned", - "var jsonData = pm.response.json();", - "pm.test(\"Response has status info\", function () {", - " pm.expect(jsonData.entity).to.be.an('object');", - " pm.expect(jsonData.entity).to.have.property('state');", - " pm.expect(jsonData.entity).to.have.property('progress'); ", - "});", + "// Get server URL from environment variable", + "const serverURL = pm.environment.get('serverURL') || pm.environment.get('baseURL'); // fallback to baseURL if serverURL is not defined", "", - "pm.test(\"Job is RUNNING\", function () {", - " var object = jsonData.entity;", - " pm.expect(object.state).to.be.eql(\"CANCELED\"); ", - " ", - "});" + "// Assuming 'jobId' is set as an environment variable", + "const jobId = pm.environment.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); ", + "", + " pm.sendRequest({", + " url:checkUrl,", + " method:'GET'", + " }, ", + " function (err, response) {", + " if (err) {", + " console.error(\"Error retrieving job status:\", err);", + " return;", + " }", + " ", + " let jsonData = response.json();", + " const jobState = jsonData.entity.state;", + " ", + " // 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'", + " }, 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.\");", + " }", + " });", + "}", + "", + "// Initial job state check", + "checkJobState(maxRetries);", + "" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "function delay(milliseconds) {", + " var start = new Date().getTime();", + " var end = start;", + " while (end - start < milliseconds) {", + " end = new Date().getTime(); ", + " }", + "}", + "", + "//delay(10000); " ], "type": "text/javascript", "packages": {} @@ -706,46 +980,71 @@ "listen": "test", "script": { "exec": [ - "pm.test(\"Status code is 200\", function () {", + "// Store the response in a variable", + "let 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);", "});", "", - "// Check if jobs are returned", - "var jsonData = pm.response.json();", - "pm.test(\"Response has jobs list\", function () {", - " pm.expect(jsonData.entity).to.have.property('jobs');", - " pm.expect(jsonData.entity.jobs).to.be.an('array'); ", + "// Check if the 'entity' object and 'jobs' array exist", + "pm.test(\"'entity' object exists and contains 'jobs' array\", function () {", + " pm.expect(response).to.have.property(\"entity\");", + " pm.expect(response.entity).to.have.property(\"jobs\").that.is.an(\"array\");", "});", "", - "// Extract JSON", - "const jobs = pm.response.json().entity.jobs;", + "// Flags to track if specific states are present", + "let hasCanceled = false;", + "let hasFailed = false;", "", - "// Validate is array", - "pm.expect(jobs).to.be.an('array');", + "// Loop through each job in the 'jobs' array to validate the conditions", + "response.entity.jobs.forEach((job, index) => {", + " // Check that 'progress' is less than 1", + " pm.test(`Job ${index + 1}: 'progress' is less than 1`, function () {", + " pm.expect(job.progress).to.be.a(\"number\").that.is.below(1);", + " });", "", - "// Create flags for states FAILED y CANCELED", - "let hasFailedJob = false;", - "let hasCancelledJob = false;", + " // Check that 'queueName' is either \"demo\" or \"fail\"", + " pm.test(`Job ${index + 1}: 'queueName' is \"demo\" or \"fail\"`, function () {", + " pm.expect(job.queueName).to.be.oneOf([\"demo\", \"fail\"]);", + " });", "", - "// Now iterate and try to find them", - "jobs.forEach(job => {", - " if (job.state === \"FAILED\") {", - " hasFailedJob = true;", - " }", + " // Check if any job has the state \"CANCELED\"", " if (job.state === \"CANCELED\") {", - " hasCancelledJob = true;", + " hasCanceled = true;", + " }", + "", + " // If job state is \"FAILED\", validate 'result' and 'errorDetail'", + " if (job.state === \"FAILED\") {", + " hasFailed = true;", + " ", + " pm.test(`Job ${index + 1}: 'result' exists and has 'errorDetail' when state is \"FAILED\"`, function () {", + " pm.expect(job).to.have.property(\"result\").that.is.an(\"object\");", + " pm.expect(job.result).to.have.property(\"errorDetail\").that.is.an(\"object\");", + " ", + " // Validate that 'errorDetail' has the expected fields", + " let errorDetail = job.result.errorDetail;", + " pm.expect(errorDetail).to.have.property(\"exceptionClass\").that.is.a(\"string\");", + " pm.expect(errorDetail).to.have.property(\"message\").that.is.a(\"string\");", + " pm.expect(errorDetail).to.have.property(\"processingStage\").that.is.a(\"string\");", + " pm.expect(errorDetail).to.have.property(\"stackTrace\").that.is.a(\"string\");", + " pm.expect(errorDetail).to.have.property(\"timestamp\").that.is.a(\"string\");", + " pm.expect(new Date(errorDetail.timestamp)).to.not.equal(\"Invalid Date\");", + " });", " }", "});", "", - "// Verify there is one is state FAILED", - "pm.test(\"Job with FAILED status exists\", function () {", - " pm.expect(hasFailedJob).to.be.true;", + "// Check that there is at least one job with state \"CANCELED\"", + "pm.test(\"At least one job has the state 'CANCELED'\", function () {", + " pm.expect(hasCanceled).to.be.true;", "});", "", - "// Verify there is one in state CANCELLED", - "pm.test(\"Job with CANCELLED status exists\", function () {", - " pm.expect(hasCancelledJob).to.be.true;", - "});" + "// Check that there is at least one job with state \"FAILED\"", + "pm.test(\"At least one job has the state 'FAILED'\", function () {", + " pm.expect(hasFailed).to.be.true;", + "});", + "" ], "type": "text/javascript", "packages": {} @@ -784,16 +1083,11 @@ } ], "auth": { - "type": "basic", - "basic": [ + "type": "bearer", + "bearer": [ { - "key": "password", - "value": "admin", - "type": "string" - }, - { - "key": "username", - "value": "admin@dotCMS.com", + "key": "token", + "value": "{{jwt}}", "type": "string" } ] @@ -805,7 +1099,45 @@ "type": "text/javascript", "packages": {}, "exec": [ - "" + " if(!pm.collectionVariables.get(\"jwt\")){", + "", + " console.log(\"generating....\")", + " const serverURL = pm.environment.get('serverURL') || pm.environment.get('baseURL'); // Get the server URL from the environment variable", + " const apiUrl = `${serverURL}/api/v1/apitoken`; // Construct the full API URL", + "", + " const username = pm.environment.get(\"user\");", + " const password = pm.environment.get(\"password\");", + " const basicAuth = Buffer.from(`${username}:${password}`).toString('base64');", + "", + " const requestOptions = {", + " url: apiUrl,", + " method: \"POST\",", + " header: {", + " \"accept\": \"*/*\",", + " \"content-type\": \"application/json\",", + " \"Authorization\": `Basic ${basicAuth}`", + " },", + " body: {", + " mode: \"raw\",", + " raw: JSON.stringify({", + " \"expirationSeconds\": 7200,", + " \"userId\": \"dotcms.org.1\",", + " \"network\": \"0.0.0.0/0\",", + " \"claims\": {\"label\": \"postman-tests\"}", + " })", + " }", + " };", + "", + " pm.sendRequest(requestOptions, function (err, response) {", + " if (err) {", + " console.log(err);", + " } else {", + " const jwt = response.json().entity.jwt;", + " pm.collectionVariables.set('jwt', jwt);", + " console.log(\"Successfully got a jwt :\" + jwt);", + " }", + " }); ", + " } " ] } }, @@ -833,7 +1165,7 @@ }, { "key": "jobId", - "value": "", + "value": "-1", "type": "string" }, { @@ -845,6 +1177,16 @@ "key": "pageSize", "value": "20", "type": "string" + }, + { + "key": "user", + "value": "admin@dotCMS.com", + "type": "string" + }, + { + "key": "password", + "value": "admin", + "type": "string" } ] } \ No newline at end of file From 4a0ab7d5923244b74cc8a628c235cf73fb202075 Mon Sep 17 00:00:00 2001 From: fabrizzio-dotCMS Date: Thu, 17 Oct 2024 21:20:34 -0600 Subject: [PATCH 2/3] #29480 --- ...ueResourceAPITests.postman_collection.json | 281 +++++++++++------- 1 file changed, 166 insertions(+), 115 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 66195b975b2b..3df2043803fb 100644 --- a/dotcms-postman/src/main/resources/postman/JobQueueResourceAPITests.postman_collection.json +++ b/dotcms-postman/src/main/resources/postman/JobQueueResourceAPITests.postman_collection.json @@ -1,11 +1,11 @@ { "info": { - "_postman_id": "30a2c62f-b9b7-4828-b4bd-17b4b78be6b5", + "_postman_id": "a12c5acf-e63e-4357-9642-07ca2795b509", "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", "_exporter_id": "10041132", - "_collection_link": "https://speeding-firefly-555540.postman.co/workspace/personal~36ad74c2-845c-4f84-8c91-495003fd59cb/collection/10041132-30a2c62f-b9b7-4828-b4bd-17b4b78be6b5?action=share&source=collection_link&creator=10041132" + "_collection_link": "https://speeding-firefly-555540.postman.co/workspace/blank~a8ffdb2b-2b56-46fa-ae3e-f4b3b0f8204a/collection/10041132-a12c5acf-e63e-4357-9642-07ca2795b509?action=share&source=collection_link&creator=10041132" }, "item": [ { @@ -176,8 +176,8 @@ "var jsonData = pm.response.json();", "pm.expect(jsonData.entity).to.be.a('String');", "// Save jobId to environment variable", - "pm.environment.set(\"jobId\", jsonData.entity);", - "let jId = pm.environment.get(\"jobId\");", + "pm.collectionVariables.set(\"jobId\", jsonData.entity);", + "let jId = pm.collectionVariables.get(\"jobId\");", "console.log(jId);" ], "type": "text/javascript", @@ -392,9 +392,9 @@ " pm.expect(jsonData.entity).to.equal('Job cancelled successfully');", "});", "", - "var jobId = pm.environment.get(\"jobId\");", + "var jobId = pm.collectionVariables.get(\"jobId\");", "console.log(\" At the time this request was sent \" + jobId);", - "pm.environment.set(\"cancelledJobId\",jobId);" + "pm.collectionVariables.set(\"cancelledJobId\",jobId);" ], "type": "text/javascript", "packages": {} @@ -403,8 +403,11 @@ { "listen": "prerequest", "script": { - "packages": {}, - "type": "text/javascript" + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {} } } ], @@ -442,7 +445,7 @@ "var jsonData = pm.response.json();", "pm.expect(jsonData.entity).to.be.a('String');", "// Save jobId to environment variable", - "pm.environment.set(\"jobId\", jsonData.entity);" + "pm.collectionVariables.set(\"jobId\", jsonData.entity);" ], "type": "text/javascript", "packages": {} @@ -583,7 +586,7 @@ "//Look for the last created job ", "let jobsArray = entity.jobs;", "", - "var jobId = pm.environment.get(\"jobId\");", + "var jobId = pm.collectionVariables.get(\"jobId\");", "pm.test(\"jobId is present in the response\", function () {", " var jobFound = jobsArray.some(function(job) {", " return job.id === jobId;", @@ -785,22 +788,27 @@ "const retryDelay = 2000; // Delay between retries in milliseconds", "", "// Get server URL from environment variable", - "const serverURL = pm.environment.get('serverURL') || pm.environment.get('baseURL'); // fallback to baseURL if serverURL is not defined", + "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.environment.get('cancelledJobId');", + "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); ", + " console.log(\"checkURL url :: \"+checkUrl); ", + " console.log(\"cancelUrl url :: \"+cancelUrl); ", + " const token = pm.collectionVariables.get('jwt');", "", " pm.sendRequest({", " url:checkUrl,", - " method:'GET'", + " method:'GET',", + " header: {", + " 'Authorization': `Bearer ${token}`, // Add Bearer token in Authorization header", + " 'Content-Type': 'application/json'", + " }", " }, ", " function (err, response) {", " if (err) {", @@ -810,6 +818,7 @@ " ", " let jsonData = response.json();", " const jobState = jsonData.entity.state;", + " console.log(jobState);", " ", " // Test for \"CANCELED\" state", " if (jobState === \"CANCELED\") {", @@ -857,15 +866,15 @@ "listen": "prerequest", "script": { "exec": [ - "function delay(milliseconds) {", - " var start = new Date().getTime();", - " var end = start;", - " while (end - start < milliseconds) {", - " end = new Date().getTime(); ", + "function sleep(milliseconds) {", + " const start = Date.now();", + " while (Date.now() - start < milliseconds) {", + " // Busy-wait loop that blocks the execution", " }", "}", "", - "//delay(10000); " + "", + "sleep(9000);" ], "type": "text/javascript", "packages": {} @@ -899,42 +908,73 @@ "listen": "test", "script": { "exec": [ - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.have.status(200);", - "});", + "// Configuration", + "const maxRetries = 5; // Maximum number of retries", + "const retryDelay = 2000; // Delay between retries in milliseconds", "", - "// Check if failed jobs are returned", - "var jsonData = pm.response.json();", - "pm.test(\"Response has failed jobs list\", function () {", - " pm.expect(jsonData.entity).to.have.property('jobs');", - " pm.expect(jsonData.entity.jobs).to.be.an('array');", - " pm.expect(jsonData.entity.jobs[0]).to.be.an('object'); ", - "});", + "// Get server URL from environment variables", + "const serverURL = pm.environment.get('serverURL') || pm.collectionVariables.get('baseUrl'); // Fallback to baseURL if serverURL is not defined", "", - "var failingJobId = pm.environment.get(\"failingJobId\"); ", - "pm.test(\"Response has failed matching objects\", function () { ", - " var jobs = jsonData.entity.jobs;", - " var failingJobId = pm.environment.get(\"failingJobId\");", - " ", - " // Filter ", - " var matchingJobs = jobs.filter(function(job) {", - " return job.id === failingJobId;", - " });", - " ", - " // Verify", - " pm.expect(matchingJobs.length).to.be.above(0);", - " ", - " // Assert", - " matchingJobs.forEach(function(job) {", - " pm.expect(job.id).to.equal(failingJobId);", - " pm.expect(job.queueName).to.equal('fail');", - " pm.expect(job.result).to.have.property('errorDetail');", - " pm.expect(job.result.errorDetail).to.have.property('exceptionClass');", - " pm.expect(job.result.errorDetail).to.have.property('message');", - " pm.expect(job.result.errorDetail).to.have.property('stackTrace');", - " pm.expect(job.result.errorDetail).to.have.property('timestamp');", + "// 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.\");", + " }", " });", - "});", + "}", + "", + "// Start job status check with the maximum number of retries", + "checkJobState(maxRetries);", "" ], "type": "text/javascript", @@ -980,70 +1020,72 @@ "listen": "test", "script": { "exec": [ - "// Store the response in a variable", - "let response = pm.response.json();", + "// Configuration", + "const maxRetries = 5; // Maximum number of retries", + "const retryDelay = 2000; // Delay between retries in milliseconds", "", - "// Validate that the response status is 200 OK", - "pm.test(\"Response status is 200\", function () {", - " pm.response.to.have.status(200);", - "});", + "// 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", "", - "// Check if the 'entity' object and 'jobs' array exist", - "pm.test(\"'entity' object exists and contains 'jobs' array\", function () {", - " pm.expect(response).to.have.property(\"entity\");", - " pm.expect(response.entity).to.have.property(\"jobs\").that.is.an(\"array\");", - "});", + "// Define the URL to check job statuses", + "const checkUrl = `${serverURL}/api/v1/jobs`;", "", - "// Flags to track if specific states are present", - "let hasCanceled = false;", - "let hasFailed = false;", + "// Function to check if there are jobs in \"FAILED\" or \"CANCELED\" state", + "function checkJobState(retriesLeft) {", "", - "// Loop through each job in the 'jobs' array to validate the conditions", - "response.entity.jobs.forEach((job, index) => {", - " // Check that 'progress' is less than 1", - " pm.test(`Job ${index + 1}: 'progress' is less than 1`, function () {", - " pm.expect(job.progress).to.be.a(\"number\").that.is.below(1);", - " });", + " 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;", + " }", "", - " // Check that 'queueName' is either \"demo\" or \"fail\"", - " pm.test(`Job ${index + 1}: 'queueName' is \"demo\" or \"fail\"`, function () {", - " pm.expect(job.queueName).to.be.oneOf([\"demo\", \"fail\"]);", - " });", + " let jsonData = response.json();", + " let jobs = jsonData.entity.jobs;", "", - " // Check if any job has the state \"CANCELED\"", - " if (job.state === \"CANCELED\") {", - " hasCanceled = true;", - " }", + " 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\");", "", - " // If job state is \"FAILED\", validate 'result' and 'errorDetail'", - " if (job.state === \"FAILED\") {", - " hasFailed = true;", - " ", - " pm.test(`Job ${index + 1}: 'result' exists and has 'errorDetail' when state is \"FAILED\"`, function () {", - " pm.expect(job).to.have.property(\"result\").that.is.an(\"object\");", - " pm.expect(job.result).to.have.property(\"errorDetail\").that.is.an(\"object\");", - " ", - " // Validate that 'errorDetail' has the expected fields", - " let errorDetail = job.result.errorDetail;", - " pm.expect(errorDetail).to.have.property(\"exceptionClass\").that.is.a(\"string\");", - " pm.expect(errorDetail).to.have.property(\"message\").that.is.a(\"string\");", - " pm.expect(errorDetail).to.have.property(\"processingStage\").that.is.a(\"string\");", - " pm.expect(errorDetail).to.have.property(\"stackTrace\").that.is.a(\"string\");", - " pm.expect(errorDetail).to.have.property(\"timestamp\").that.is.a(\"string\");", - " pm.expect(new Date(errorDetail.timestamp)).to.not.equal(\"Invalid Date\");", - " });", - " }", - "});", + " // Postman test to validate that there are jobs with \"FAILED\" and \"CANCELED\" statuses", + " pm.test(\"There are jobs in 'FAILED' and 'CANCELED' state\", function () {", + " pm.expect(hasFailed).to.be.true;", + " pm.expect(hasCanceled).to.be.true;", + " });", "", - "// Check that there is at least one job with state \"CANCELED\"", - "pm.test(\"At least one job has the state 'CANCELED'\", 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.\");", + " }", + " });", + "}", "", - "// Check that there is at least one job with state \"FAILED\"", - "pm.test(\"At least one job has the state 'FAILED'\", function () {", - " pm.expect(hasFailed).to.be.true;", - "});", + "// Start checking job statuses with the maximum number of retries", + "checkJobState(maxRetries);", "" ], "type": "text/javascript", @@ -1099,14 +1141,14 @@ "type": "text/javascript", "packages": {}, "exec": [ - " if(!pm.collectionVariables.get(\"jwt\")){", - "", + " ", + "if(!pm.collectionVariables.get('jwt')){", " console.log(\"generating....\")", - " const serverURL = pm.environment.get('serverURL') || pm.environment.get('baseURL'); // Get the server URL from the environment variable", + " const serverURL = pm.environment.get('serverURL') || pm.collectionVariables.get('baseUrl'); // Get the server URL from the environment variable", " const apiUrl = `${serverURL}/api/v1/apitoken`; // Construct the full API URL", "", - " const username = pm.environment.get(\"user\");", - " const password = pm.environment.get(\"password\");", + " const username = pm.environment.get(\"user\") || pm.collectionVariables.get('user'); ", + " const password = pm.environment.get(\"password\") || pm.collectionVariables.get('password');", " const basicAuth = Buffer.from(`${username}:${password}`).toString('base64');", "", " const requestOptions = {", @@ -1137,7 +1179,7 @@ " console.log(\"Successfully got a jwt :\" + jwt);", " }", " }); ", - " } " + "} " ] } }, @@ -1168,6 +1210,11 @@ "value": "-1", "type": "string" }, + { + "key": "cancelledJobId", + "value": "-1", + "type": "string" + }, { "key": "page", "value": "1", @@ -1187,6 +1234,10 @@ "key": "password", "value": "admin", "type": "string" + }, + { + "key": "jwt", + "value": "" } ] } \ No newline at end of file From de63fdf3b4ab3756a6846a2bf726cd5a4457bfb3 Mon Sep 17 00:00:00 2001 From: fabrizzio-dotCMS Date: Thu, 17 Oct 2024 23:06:38 -0600 Subject: [PATCH 3/3] #299480 --- .../business/error/RetryStrategyProducer.java | 2 +- ...eueResourceAPITests.postman_collection.json | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/dotCMS/src/main/java/com/dotcms/jobs/business/error/RetryStrategyProducer.java b/dotCMS/src/main/java/com/dotcms/jobs/business/error/RetryStrategyProducer.java index ca3b48b8fb7e..2b9452d66713 100644 --- a/dotCMS/src/main/java/com/dotcms/jobs/business/error/RetryStrategyProducer.java +++ b/dotCMS/src/main/java/com/dotcms/jobs/business/error/RetryStrategyProducer.java @@ -28,7 +28,7 @@ public class RetryStrategyProducer { // The maximum number of retry attempts allowed static final int DEFAULT_RETRY_STRATEGY_MAX_RETRIES = Config.getIntProperty( - "DEFAULT_RETRY_STRATEGY_MAX_RETRIES", 3 + "DEFAULT_RETRY_STRATEGY_MAX_RETRIES", 1 ); /** 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 3df2043803fb..f7aa1934dadc 100644 --- a/dotcms-postman/src/main/resources/postman/JobQueueResourceAPITests.postman_collection.json +++ b/dotcms-postman/src/main/resources/postman/JobQueueResourceAPITests.postman_collection.json @@ -785,7 +785,7 @@ "exec": [ "// Configuration", "const maxRetries = 5; // Number of times to retry", - "const retryDelay = 2000; // Delay between retries in milliseconds", + "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", @@ -831,7 +831,11 @@ " // Send a cancel POST request and retry", " pm.sendRequest({", " url: cancelUrl,", - " method: 'POST'", + " 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);", @@ -1057,9 +1061,13 @@ " 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\" and \"CANCELED\" statuses", - " pm.test(\"There are jobs in 'FAILED' and 'CANCELED' state\", function () {", - " pm.expect(hasFailed).to.be.true;", + " // 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;", " });", "",