From 4edfb8db3de91d6d7b2773f2f6b011e69cac2867 Mon Sep 17 00:00:00 2001 From: fabrizzio-dotCMS Date: Wed, 9 Oct 2024 14:58:11 -0600 Subject: [PATCH] #29480 --- .../rest/api/v1/job/JobQueueHelper.java | 13 +- .../src/test/java/com/dotcms/MainSuite2b.java | 2 + .../v1/job/JobQueueHelperIntegrationTest.java | 202 ++++++++++++++++++ 3 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 dotcms-integration/src/test/java/com/dotcms/rest/api/v1/job/JobQueueHelperIntegrationTest.java diff --git a/dotCMS/src/main/java/com/dotcms/rest/api/v1/job/JobQueueHelper.java b/dotCMS/src/main/java/com/dotcms/rest/api/v1/job/JobQueueHelper.java index c815414c2e04..cf990ad0fac9 100644 --- a/dotCMS/src/main/java/com/dotcms/rest/api/v1/job/JobQueueHelper.java +++ b/dotCMS/src/main/java/com/dotcms/rest/api/v1/job/JobQueueHelper.java @@ -16,6 +16,7 @@ import com.dotmarketing.exception.DotDataException; import com.dotmarketing.util.Logger; import com.fasterxml.jackson.core.JsonProcessingException; +import com.google.common.annotations.VisibleForTesting; import java.io.InputStream; import java.lang.reflect.Constructor; import java.time.format.DateTimeFormatter; @@ -106,6 +107,16 @@ public JobQueueHelper(JobQueueManagerAPI jobQueueManagerAPI, JobProcessorScanner this.scanner = scanner; } + /** + * Registers a processor + * @param queueName The name of the queue + * @param processor Class of the processor + */ + @VisibleForTesting + void registerProcessor(final String queueName, final Class processor){ + jobQueueManagerAPI.registerProcessor(queueName.toLowerCase(), processor); + } + /** * creates a job * @param queueName @@ -223,7 +234,7 @@ Set getQueueNames(){ * @param params The params * @param request The request */ - private void handleUploadIfPresent(final JobParams form, Map params, HttpServletRequest request) { + void handleUploadIfPresent(final JobParams form, Map params, HttpServletRequest request) { final InputStream fileInputStream = form.getFileInputStream(); final FormDataContentDisposition contentDisposition = form.getContentDisposition(); if (null != fileInputStream && null != contentDisposition) { diff --git a/dotcms-integration/src/test/java/com/dotcms/MainSuite2b.java b/dotcms-integration/src/test/java/com/dotcms/MainSuite2b.java index c32833b30070..0eed1a5ed945 100644 --- a/dotcms-integration/src/test/java/com/dotcms/MainSuite2b.java +++ b/dotcms-integration/src/test/java/com/dotcms/MainSuite2b.java @@ -79,6 +79,7 @@ import com.dotcms.rest.api.v1.asset.AssetPathResolverImplIntegrationTest; import com.dotcms.rest.api.v1.asset.WebAssetHelperIntegrationTest; import com.dotcms.rest.api.v1.authentication.ResetPasswordTokenUtilTest; +import com.dotcms.rest.api.v1.job.JobQueueHelperIntegrationTest; import com.dotcms.rest.api.v1.menu.MenuResourceTest; import com.dotcms.rest.api.v1.system.ConfigurationHelperTest; import com.dotcms.rest.api.v1.taillog.TailLogResourceTest; @@ -323,6 +324,7 @@ Task240606AddVariableColumnToWorkflowTest.class, OpenAIContentPromptActionletTest.class, JobQueueManagerAPITest.class, + JobQueueHelperIntegrationTest.class, ConfigUtilsTest.class, SimpleInjectionIT.class, LegacyJSONObjectRenderTest.class, diff --git a/dotcms-integration/src/test/java/com/dotcms/rest/api/v1/job/JobQueueHelperIntegrationTest.java b/dotcms-integration/src/test/java/com/dotcms/rest/api/v1/job/JobQueueHelperIntegrationTest.java new file mode 100644 index 000000000000..ea9ecdefc96f --- /dev/null +++ b/dotcms-integration/src/test/java/com/dotcms/rest/api/v1/job/JobQueueHelperIntegrationTest.java @@ -0,0 +1,202 @@ +package com.dotcms.rest.api.v1.job; + +import static org.junit.Assert.assertThrows; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.dotcms.cdi.CDIUtils; +import com.dotcms.jobs.business.job.Job; +import com.dotcms.jobs.business.processor.JobProcessor; +import com.dotcms.util.IntegrationTestInitService; +import com.dotmarketing.exception.DoesNotExistException; +import com.dotmarketing.exception.DotDataException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.liferay.portal.model.User; +import com.liferay.portal.util.WebKeys; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; +import org.glassfish.jersey.media.multipart.FormDataContentDisposition; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +/** + * Integration test for the JobQueueHelper class + * Helper add functionality to consume JobQueueManagerAPI + * Here we test those functionalities, methods that simply call the JobQueueManagerAPI are not tested + */ +public class JobQueueHelperIntegrationTest { + + static JobQueueHelper jobQueueHelper; + + @BeforeAll + static void setUp() throws Exception { + // Initialize the test environment + IntegrationTestInitService.getInstance().init(); + jobQueueHelper = CDIUtils.getBean(JobQueueHelper.class).orElseThrow(() -> new IllegalStateException("JobQueueHelper Bean not found")); + } + + @Test + void testEmptyParams(){ + assertThrows(IllegalArgumentException.class, () -> { + jobQueueHelper.createJob("any", new JobParams(), mock(HttpServletRequest.class)); + }); + } + + @Test + void testWithValidParamsButInvalidQueueName(){ + final JobParams jobParams = new JobParams(); + jobParams.setJsonParams("{}"); + assertThrows(DoesNotExistException.class, () -> { + jobQueueHelper.createJob("nonExisting", jobParams, mock(HttpServletRequest.class)); + }); + } + + public static class DemoJobProcessor implements JobProcessor { + + public DemoJobProcessor() { + // Do nothing + } + + @Override + public void process(Job job) { + // Do nothing + } + + @Override + public Map getResultMetadata(Job job) { + return Map.of(); + } + } + + /** + * Test with valid parameters and queue name + * Given scenario: create a job with valid parameters and queue name + * Expected result: the job is created and the queue name is added to the list of queue names + * @throws DotDataException + * @throws JsonProcessingException + */ + @Test + void testWithValidParamsAndQueueName() throws DotDataException, JsonProcessingException { + jobQueueHelper.registerProcessor("demoQueue", DemoJobProcessor.class); + + final JobParams jobParams = new JobParams(); + jobParams.setJsonParams("{}"); + + final String jobId = jobQueueHelper.createJob("demoQueue", jobParams, + mock(HttpServletRequest.class)); + + Assertions.assertNotNull(jobId); + final Job job = jobQueueHelper.getJob(jobId); + Assertions.assertNotNull(job); + Assertions.assertEquals(jobId, job.id()); + Assertions.assertTrue(jobQueueHelper.getQueueNames().contains("demoQueue".toLowerCase())); + } + + /** + * Given scenario: create a job with valid parameters and queue name + * Expected result: the job is created and it is watchable + * @throws DotDataException + * @throws JsonProcessingException + */ + @Test + void testIsWatchable() throws DotDataException, JsonProcessingException { + jobQueueHelper.registerProcessor("testQueue", DemoJobProcessor.class); + final JobParams jobParams = new JobParams(); + jobParams.setJsonParams("{}"); + final String jobId = jobQueueHelper.createJob("testQueue", jobParams, + mock(HttpServletRequest.class)); + Assertions.assertNotNull(jobId); + final Job job = jobQueueHelper.getJob(jobId); + assertFalse(jobQueueHelper.isNotWatchable(job)); + } + + + /** + * Given scenario: create a job with valid parameters and queue name + * Expected result: the job is created and the status info is returned + * @throws DotDataException + * @throws JsonProcessingException + */ + @Test + void testGetStatusInfo() throws DotDataException, JsonProcessingException { + jobQueueHelper.registerProcessor("testQueue", DemoJobProcessor.class); + final JobParams jobParams = new JobParams(); + jobParams.setJsonParams("{}"); + final String jobId = jobQueueHelper.createJob("testQueue", jobParams, + mock(HttpServletRequest.class)); + Assertions.assertNotNull(jobId); + final Job job = jobQueueHelper.getJob(jobId); + final Map info = jobQueueHelper.getJobStatusInfo(job); + Assertions.assertTrue(info.containsKey("state")); + Assertions.assertTrue(info.containsKey("progress")); + Assertions.assertTrue(info.containsKey("startedAt")); + Assertions.assertTrue(info.containsKey("finishedAt")); + } + + /** + * Given scenario: call cancel Job with an invalid job id + * Expected result: we should get a DoesNotExistException + */ + @Test + void testCancelNonExistingJob(){ + assertThrows(DoesNotExistException.class, () -> { + jobQueueHelper.cancelJob("nonExisting" ); + }); + } + + /** + * Mock the request + * @return a mocked HttpServletRequest + */ + HttpServletRequest mockRequest(){ + HttpServletRequest request = mock(HttpServletRequest.class); + when(request.getParameter("param1")).thenReturn("value1"); + when(request.getParameter("param2")).thenReturn("value2"); + when(request.getParameter("param3")).thenReturn("value3"); + when(request.getParameterNames()).thenReturn(java.util.Collections.enumeration(java.util.Arrays.asList("param1", "param2", "param3"))); + HttpSession session = mock(HttpSession.class); + when(session.getId()).thenReturn("mockSessionId123"); + when(request.getSession()).thenReturn(session); + + User user = mock(User.class); + when(user.getUserId()).thenReturn("mockUserId123"); + when(request.getAttribute(WebKeys.USER)).thenReturn(user); + return request; + } + + FormDataContentDisposition mockFormDataContentDisposition(){ + FormDataContentDisposition formDataContentDisposition = mock(FormDataContentDisposition.class); + when(formDataContentDisposition.getFileName()).thenReturn("test.txt"); + return formDataContentDisposition; + } + + /** + * Test file upload + * Given scenario: upload a file + * Expected result: the file is uploaded and the request fingerprint and temp file id are added to the map + * @throws IOException + */ + @Test + void TestFileUpload() throws IOException { + + final File tempFile = File.createTempFile("test", "test"); + JobParams jobParams = new JobParams(); + jobParams.setJsonParams("{}"); + jobParams.setParams(Map.of()); + jobParams.setFileInputStream(new FileInputStream(tempFile)); + jobParams.setContentDisposition(mockFormDataContentDisposition()); + + final Map map = new HashMap<>(); + jobQueueHelper.handleUploadIfPresent(jobParams,map,mockRequest()); + Assertions.assertTrue(map.containsKey("requestFingerPrint")); + Assertions.assertTrue(map.containsKey("tempFileId")); + } + +}