diff --git a/.github/workflows/cicd_1-pr.yml b/.github/workflows/cicd_1-pr.yml index 83e29908aaf1..505c3800547c 100644 --- a/.github/workflows/cicd_1-pr.yml +++ b/.github/workflows/cicd_1-pr.yml @@ -69,8 +69,7 @@ jobs: postman: ${{ needs.initialize.outputs.backend == 'true' }} frontend: ${{ needs.initialize.outputs.frontend == 'true' }} cli: ${{ needs.initialize.outputs.cli == 'true' }} -# TODO: remove this param after testing E2E tests invocation - e2e: true + e2e: ${{ needs.initialize.outputs.build }} secrets: DOTCMS_LICENSE: ${{ secrets.DOTCMS_LICENSE }} diff --git a/.github/workflows/cicd_2-merge-queue.yml b/.github/workflows/cicd_2-merge-queue.yml index 1e9479bea03c..84191b7c483f 100644 --- a/.github/workflows/cicd_2-merge-queue.yml +++ b/.github/workflows/cicd_2-merge-queue.yml @@ -26,6 +26,8 @@ jobs: postman: ${{ needs.initialize.outputs.backend == 'true' }} frontend: ${{ needs.initialize.outputs.frontend == 'true' }} cli: ${{ needs.initialize.outputs.cli == 'true' }} +# This will probably need to be re-evaluated, that is if it makes sense to tun E2E tests at the merge queue +# e2e: ${{ needs.initialize.outputs.build }} secrets: DOTCMS_LICENSE: ${{ secrets.DOTCMS_LICENSE }} finalize: diff --git a/.github/workflows/cicd_3-trunk.yml b/.github/workflows/cicd_3-trunk.yml index d219b6fa4a8a..ab3e724ca8a1 100644 --- a/.github/workflows/cicd_3-trunk.yml +++ b/.github/workflows/cicd_3-trunk.yml @@ -66,7 +66,6 @@ jobs: with: run-all-tests: ${{ inputs.run-all-tests || false }} artifact-run-id: ${{ needs.initialize.outputs.artifact-run-id }} - e2e: true secrets: DOTCMS_LICENSE: ${{ secrets.DOTCMS_LICENSE }} permissions: diff --git a/dotCMS/src/main/java/com/dotcms/analytics/content/ContentAnalyticsAPI.java b/dotCMS/src/main/java/com/dotcms/analytics/content/ContentAnalyticsAPI.java index 76694ea7a331..26531579feae 100644 --- a/dotCMS/src/main/java/com/dotcms/analytics/content/ContentAnalyticsAPI.java +++ b/dotCMS/src/main/java/com/dotcms/analytics/content/ContentAnalyticsAPI.java @@ -1,6 +1,7 @@ package com.dotcms.analytics.content; import com.dotcms.analytics.query.AnalyticsQuery; +import com.dotcms.cube.CubeJSQuery; import com.liferay.portal.model.User; /** @@ -14,6 +15,20 @@ */ public interface ContentAnalyticsAPI { + /** + * Run a report based on an analytics query + * @param query + * @param user + * @return ReportResponse + */ ReportResponse runReport(final AnalyticsQuery query, final User user); + /** + * Runs a raw report based on a cubeJS query + * @param cubeJSQuery + * @param user + * @return ReportResponse + */ + ReportResponse runRawReport(CubeJSQuery cubeJSQuery, User user); + } diff --git a/dotCMS/src/main/java/com/dotcms/analytics/content/ContentAnalyticsAPIImpl.java b/dotCMS/src/main/java/com/dotcms/analytics/content/ContentAnalyticsAPIImpl.java index 9fff54bf4257..2417314de079 100644 --- a/dotCMS/src/main/java/com/dotcms/analytics/content/ContentAnalyticsAPIImpl.java +++ b/dotCMS/src/main/java/com/dotcms/analytics/content/ContentAnalyticsAPIImpl.java @@ -1,6 +1,7 @@ package com.dotcms.analytics.content; import com.dotcms.analytics.query.AnalyticsQuery; +import com.dotcms.cube.CubeJSQuery; import com.dotmarketing.util.Logger; import com.liferay.portal.model.User; @@ -31,4 +32,11 @@ public ReportResponse runReport(final AnalyticsQuery query, final User user) { return this.contentAnalyticsFactory.getReport(query, user); } + @Override + public ReportResponse runRawReport(CubeJSQuery cubeJSQuery, User user) { + Logger.debug(this, ()-> "Running the report for the raw query: " + cubeJSQuery); + // note: should check any permissions for an user. + return this.contentAnalyticsFactory.getRawReport(cubeJSQuery, user); + } + } diff --git a/dotCMS/src/main/java/com/dotcms/analytics/content/ContentAnalyticsFactory.java b/dotCMS/src/main/java/com/dotcms/analytics/content/ContentAnalyticsFactory.java index 9f2f771a48ae..2821e6de5009 100644 --- a/dotCMS/src/main/java/com/dotcms/analytics/content/ContentAnalyticsFactory.java +++ b/dotCMS/src/main/java/com/dotcms/analytics/content/ContentAnalyticsFactory.java @@ -1,6 +1,7 @@ package com.dotcms.analytics.content; import com.dotcms.analytics.query.AnalyticsQuery; +import com.dotcms.cube.CubeJSQuery; import com.liferay.portal.model.User; /** @@ -20,4 +21,13 @@ public interface ContentAnalyticsFactory { */ ReportResponse getReport(final AnalyticsQuery query, final User user); + /** + * Runs the raw report based on the cube js query and user. + * + * @param query the query to run the report. + * @param user the user to run the report. + * @return the report response. + */ + ReportResponse getRawReport(final CubeJSQuery query, final User user); + } diff --git a/dotCMS/src/main/java/com/dotcms/analytics/content/ContentAnalyticsFactoryImpl.java b/dotCMS/src/main/java/com/dotcms/analytics/content/ContentAnalyticsFactoryImpl.java index b7338db2329d..be1e7f999d5e 100644 --- a/dotCMS/src/main/java/com/dotcms/analytics/content/ContentAnalyticsFactoryImpl.java +++ b/dotCMS/src/main/java/com/dotcms/analytics/content/ContentAnalyticsFactoryImpl.java @@ -41,6 +41,20 @@ public ReportResponse getReport(final AnalyticsQuery query, final User user) { Logger.debug(this, ()-> "Getting the report for the query: " + query); try { final CubeJSQuery cubeJSQuery = this.queryParser.parseQueryToCubeQuery(query); + return getRawReport(cubeJSQuery, user); + } catch (Exception e) { + + Logger.error(this, e.getMessage(), e); + throw new DotRuntimeException(e); + } + } + + @Override + public ReportResponse getRawReport(final CubeJSQuery cubeJSQuery, final User user) { + + try { + + Logger.debug(this, ()-> "Getting the report for the raw query: " + cubeJSQuery); final CubeJSClient cubeClient = cubeJSClientFactory.create(user); return toReportResponse(cubeClient.send(cubeJSQuery)); } catch (DotDataException| DotSecurityException e) { diff --git a/dotCMS/src/main/java/com/dotcms/analytics/content/ReportResponse.java b/dotCMS/src/main/java/com/dotcms/analytics/content/ReportResponse.java index dc1ca92650a8..10ca5a528641 100644 --- a/dotCMS/src/main/java/com/dotcms/analytics/content/ReportResponse.java +++ b/dotCMS/src/main/java/com/dotcms/analytics/content/ReportResponse.java @@ -21,4 +21,11 @@ public ReportResponse(final List results){ public List getResults() { return results; } + + @Override + public String toString() { + return "ReportResponse{" + + "results=" + results + + '}'; + } } diff --git a/dotCMS/src/main/java/com/dotcms/analytics/model/ResultSetItem.java b/dotCMS/src/main/java/com/dotcms/analytics/model/ResultSetItem.java index e249fd3b2bd7..6dd93abc9747 100644 --- a/dotCMS/src/main/java/com/dotcms/analytics/model/ResultSetItem.java +++ b/dotCMS/src/main/java/com/dotcms/analytics/model/ResultSetItem.java @@ -31,4 +31,10 @@ public Map getAll(){ return new HashMap<>(item); } + @Override + public String toString() { + return "ResultSetItem{" + + "item=" + item + + '}'; + } } diff --git a/dotCMS/src/main/java/com/dotcms/analytics/viewtool/AnalyticsTool.java b/dotCMS/src/main/java/com/dotcms/analytics/viewtool/AnalyticsTool.java new file mode 100644 index 000000000000..1890d00d802a --- /dev/null +++ b/dotCMS/src/main/java/com/dotcms/analytics/viewtool/AnalyticsTool.java @@ -0,0 +1,169 @@ +package com.dotcms.analytics.viewtool; + +import com.dotcms.analytics.content.ContentAnalyticsAPI; +import com.dotcms.analytics.content.ReportResponse; +import com.dotcms.analytics.query.AnalyticsQuery; +import com.dotcms.analytics.query.AnalyticsQueryParser; +import com.dotcms.cdi.CDIUtils; +import com.dotcms.cube.CubeJSQuery; +import com.dotcms.rest.api.v1.DotObjectMapperProvider; +import com.dotmarketing.business.web.UserWebAPI; +import com.dotmarketing.business.web.WebAPILocator; +import com.dotmarketing.exception.DotRuntimeException; +import com.dotmarketing.util.Logger; +import com.liferay.portal.model.User; +import org.apache.velocity.tools.view.context.ViewContext; +import org.apache.velocity.tools.view.tools.ViewTool; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +/** + * This class is a ViewTool that can be used to access the analytics data. + * @author jsanca + */ +public class AnalyticsTool implements ViewTool { + + private final ContentAnalyticsAPI contentAnalyticsAPI; + private final AnalyticsQueryParser analyticsQueryParser; + private final UserWebAPI userWebAPI; + + private User user = null; + + public AnalyticsTool() { + this(getContentAnalyticsAPI(), + getAnalyticsQueryParser(), + WebAPILocator.getUserWebAPI()); + } + + private static ContentAnalyticsAPI getContentAnalyticsAPI() { + final Optional contentAnalyticsAPI = CDIUtils.getBean(ContentAnalyticsAPI.class); + if (!contentAnalyticsAPI.isPresent()) { + throw new DotRuntimeException("Could not instance ContentAnalyticsAPI"); + } + return contentAnalyticsAPI.get(); + } + + private static AnalyticsQueryParser getAnalyticsQueryParser() { + final Optional queryParserOptional = CDIUtils.getBean(AnalyticsQueryParser.class); + if (!queryParserOptional.isPresent()) { + throw new DotRuntimeException("Could not instance AnalyticsQueryParser"); + } + return queryParserOptional.get(); + } + + public AnalyticsTool(final ContentAnalyticsAPI contentAnalyticsAPI, + final AnalyticsQueryParser analyticsQueryParser, + final UserWebAPI userWebAPI) { + + this.contentAnalyticsAPI = contentAnalyticsAPI; + this.analyticsQueryParser = analyticsQueryParser; + this.userWebAPI = userWebAPI; + } + + @Override + public void init(final Object initData) { + + if (initData instanceof ViewContext) { + + final HttpServletRequest request = ((ViewContext) initData).getRequest(); + final HttpSession session = request.getSession(false); + + if (session != null) { + try { + user = userWebAPI.getLoggedInUser(request); + } catch (DotRuntimeException e) { + Logger.error(this.getClass(), e.getMessage()); + } + } + } + } + + /** + * Runs an analytics report based on the string json query. + * example: + * + * #set($query = "{ + * "dimensions": ["Events.referer", "Events.experiment", "Events.variant", "Events.utcTime", "Events.url", "Events.lookBackWindow", "Events.eventType"], + * "measures": ["Events.count", "Events.uniqueCount"], + * "filters": "Events.variant = ['B'] or Events.experiments = ['B']", + * "limit":100, + * "offset":1, + * "timeDimensions":"Events.day day", + * "orders":"Events.day ASC" + * }") + * + * $analytics.runReportFromJson($query) + * + * @param query + * @return + */ + public ReportResponse runReportFromJson(final String query) { + + Logger.debug(this, () -> "Running report from json: " + query); + return contentAnalyticsAPI.runReport(this.analyticsQueryParser.parseJsonToQuery(query), user); + } + + /** + * Runs an analytics report based on Map query. + * example: + * + * #set ($myQuery = {}) + * $myMap.put('dimensions', ["Events.referer", "Events.experiment", "Events.variant", "Events.utcTime", "Events.url", "Events.lookBackWindow", "Events.eventType"]) + * $myMap.put('measures', ["Events.count", "Events.uniqueCount"]) + * $myMap.put('filters', "Events.variant = ['B'] or Events.experiments = ['B']") + * $myMap.put('limit', 100) + * $myMap.put('offset', 1) + * $myMap.put('timeDimensions', "Events.day day") + * $myMap.put('orders', "Events.day ASC") + * + * $analytics.runReportFromMap($myQuery) + * + * @param query + * @return + */ + public ReportResponse runReportFromMap(final Map query) { + + if (Objects.isNull(query)) { + throw new IllegalArgumentException("Query can not be null"); + } + + Logger.debug(this, () -> "Running report from map: " + query); + final AnalyticsQuery analyticsQuery = DotObjectMapperProvider.getInstance() + .getDefaultObjectMapper().convertValue(query, AnalyticsQuery.class); + return contentAnalyticsAPI.runReport(analyticsQuery, user); + } + + /** + * Creates a CubeJSQuery.Builder instance + * @return + */ + public CubeJSQuery.Builder createCubeJSQueryBuilder() { + return new CubeJSQuery.Builder(); + } + + /** + * Runs an analytics report based cube js raw json string query + * + * example: + * + * #set($query = $analytics.createCubeJSQueryBuilder()) + * $query.dimensions("Events.experiment", "Events.variant") + * $analytics.runRawReport($query.build()) + * + * @param query + * @return + */ + public ReportResponse runRawReport(final CubeJSQuery query) { + + if (Objects.isNull(query)) { + throw new IllegalArgumentException("Query can not be null"); + } + + Logger.debug(this, () -> "Running report from raw query: " + query); + return contentAnalyticsAPI.runRawReport(query, user); + } +} diff --git a/dotCMS/src/main/java/com/dotcms/cube/CubeJSQuery.java b/dotCMS/src/main/java/com/dotcms/cube/CubeJSQuery.java index 882eba39695a..d63209147fa7 100644 --- a/dotCMS/src/main/java/com/dotcms/cube/CubeJSQuery.java +++ b/dotCMS/src/main/java/com/dotcms/cube/CubeJSQuery.java @@ -1,19 +1,17 @@ package com.dotcms.cube; - -import com.dotcms.api.system.event.SystemEventsFactory; +import com.dotcms.cube.filters.Filter; import com.dotcms.cube.filters.Filter.Order; import com.dotcms.cube.filters.LogicalFilter; import com.dotcms.cube.filters.SimpleFilter; import com.dotcms.cube.filters.SimpleFilter.Operator; -import com.dotcms.cube.filters.Filter; -import com.dotcms.experiments.business.result.ExperimentResults; -import com.dotcms.experiments.business.result.ExperimentResults.Builder; import com.dotcms.util.DotPreconditions; import com.dotcms.util.JsonUtil; import com.dotmarketing.util.UtilMethods; import com.google.common.collect.Iterables; +import org.jetbrains.annotations.NotNull; + import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; @@ -24,16 +22,6 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Set; -import java.util.TreeSet; -import java.util.stream.Collectors; -import org.jetbrains.annotations.NotNull; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import java.util.stream.Collectors; diff --git a/dotCMS/src/main/java/com/dotcms/rest/api/v1/analytics/content/ContentAnalyticsResource.java b/dotCMS/src/main/java/com/dotcms/rest/api/v1/analytics/content/ContentAnalyticsResource.java index de0b8a9a4e82..49761e1249bc 100644 --- a/dotCMS/src/main/java/com/dotcms/rest/api/v1/analytics/content/ContentAnalyticsResource.java +++ b/dotCMS/src/main/java/com/dotcms/rest/api/v1/analytics/content/ContentAnalyticsResource.java @@ -28,6 +28,7 @@ import javax.ws.rs.core.MediaType; /** + * Resource class that exposes endpoints to query content analytics data. * This REST Endpoint exposes different operations to query Content Analytics data. Content * Analytics will enable customers to track the health and engagement of their content at the level * of individual content items. @@ -48,6 +49,7 @@ public ContentAnalyticsResource() { this(CDIUtils.getBean(ContentAnalyticsAPI.class).orElseGet(APILocator::getContentAnalyticsAPI)); } + //@Inject @VisibleForTesting public ContentAnalyticsResource(final ContentAnalyticsAPI contentAnalyticsAPI) { this(new WebResource(), contentAnalyticsAPI); @@ -60,12 +62,14 @@ public ContentAnalyticsResource(final WebResource webResource, this.contentAnalyticsAPI = contentAnalyticsAPI; } - @POST - @Path("/_query") - @JSONP - @NoCache - @Consumes(MediaType.APPLICATION_JSON) - @Produces({MediaType.APPLICATION_JSON, "application/javascript"}) + /** + * Query Content Analytics data. + * + * @param request the HTTP request. + * @param response the HTTP response. + * @param queryForm the query form. + * @return the report response entity view. + */ @Operation( operationId = "postContentAnalyticsQuery", summary = "Retrieve Content Analytics data", @@ -101,18 +105,27 @@ public ContentAnalyticsResource(final WebResource webResource, @ApiResponse(responseCode = "500", description = "Internal Server Error") } ) + @POST + @Path("/_query") + @JSONP + @NoCache + @Consumes(MediaType.APPLICATION_JSON) + @Produces({MediaType.APPLICATION_JSON, "application/javascript"}) public ReportResponseEntityView query(@Context final HttpServletRequest request, @Context final HttpServletResponse response, final QueryForm queryForm) { + final InitDataObject initDataObject = new WebResource.InitBuilder(this.webResource) .requestAndResponse(request, response) .requiredBackendUser(true) .rejectWhenNoUser(true) .init(); + + final User user = initDataObject.getUser(); DotPreconditions.checkNotNull(queryForm, IllegalArgumentException.class, "The 'query' JSON data cannot be null"); Logger.debug(this, () -> "Querying content analytics data with the form: " + queryForm); final ReportResponse reportResponse = - this.contentAnalyticsAPI.runReport(queryForm.getQuery(), initDataObject.getUser()); + this.contentAnalyticsAPI.runReport(queryForm.getQuery(), user); return new ReportResponseEntityView(reportResponse); } diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/business/HostAPIImpl.java b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/business/HostAPIImpl.java index 504083e15fbe..b8b8c685ce7f 100644 --- a/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/business/HostAPIImpl.java +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/contentlet/business/HostAPIImpl.java @@ -121,31 +121,17 @@ public Host findDefaultHost(User user, boolean respectFrontendRoles) throws DotS @Override @CloseDBIfOpened public Host resolveHostName(String serverName, User user, boolean respectFrontendRoles) throws DotDataException, DotSecurityException { + User systemUser = APILocator.systemUser(); Host host; - final Host cachedHostByAlias = hostCache.getHostByAlias(serverName); - if (UtilMethods.isSet(() -> cachedHostByAlias.getIdentifier())) { - if (HostCache.CACHE_404_HOST.equals(cachedHostByAlias.getIdentifier())) { - return null; - } - host = cachedHostByAlias; - } else { - final User systemUser = APILocator.systemUser(); - try { - final Optional optional = resolveHostNameWithoutDefault(serverName, systemUser, respectFrontendRoles); - host = optional.isPresent() ? optional.get() : findDefaultHost(systemUser, respectFrontendRoles); - } catch (Exception e) { - host = findDefaultHost(systemUser, respectFrontendRoles); - } - - if (host != null) { - hostCache.addHostAlias(serverName, host); - } else { - hostCache.addHostAlias(serverName, HostCache.cache404Contentlet); - } - } - if (host != null) { - checkSitePermission(user, respectFrontendRoles, host); + try { + final Optional optional = + resolveHostNameWithoutDefault(serverName, systemUser, respectFrontendRoles); + host = optional.isPresent() ? optional.get() : findDefaultHost(systemUser, respectFrontendRoles); + } catch (Exception e) { + Logger.debug(this, "Exception resolving host using default", e); + host = findDefaultHost(systemUser, respectFrontendRoles); } + checkSitePermission(user, respectFrontendRoles, host); return host; } diff --git a/dotCMS/src/main/webapp/WEB-INF/toolbox.xml b/dotCMS/src/main/webapp/WEB-INF/toolbox.xml index dbc7172ebbaa..2371ca535fdb 100644 --- a/dotCMS/src/main/webapp/WEB-INF/toolbox.xml +++ b/dotCMS/src/main/webapp/WEB-INF/toolbox.xml @@ -322,4 +322,9 @@ request com.dotcms.ai.viewtool.AIViewTool + + analytics + request + com.dotcms.analytics.viewtool.AnalyticsTool + diff --git a/dotCMS/src/test/java/com/dotcms/analytics/viewtool/AnalyticsToolTest.java b/dotCMS/src/test/java/com/dotcms/analytics/viewtool/AnalyticsToolTest.java new file mode 100644 index 000000000000..2c587385a8c7 --- /dev/null +++ b/dotCMS/src/test/java/com/dotcms/analytics/viewtool/AnalyticsToolTest.java @@ -0,0 +1,246 @@ +package com.dotcms.analytics.viewtool; + +import com.dotcms.analytics.content.ContentAnalyticsAPI; +import com.dotcms.analytics.content.ReportResponse; +import com.dotcms.analytics.query.AnalyticsQueryParser; +import com.dotcms.cube.CubeJSQuery; +import com.dotmarketing.business.web.UserWebAPI; +import com.dotmarketing.exception.DotRuntimeException; +import com.liferay.portal.model.User; +import org.apache.velocity.tools.view.context.ViewContext; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Test class for AnalyticsTool + * @author jsanca + */ +public class AnalyticsToolTest { + + /** + * Method to test: {@link AnalyticsTool#runReportFromJson(String)} + * Given Scenario: Sending a null as json + * ExpectedResult: Should throw IllegalArgumentException + */ + @Test(expected = IllegalArgumentException.class) + public void test_run_report_from_json_npe() { + + final HttpServletRequest request = Mockito.mock(HttpServletRequest.class); + final HttpSession session = Mockito.mock(HttpSession.class); + final ContentAnalyticsAPI contentAnalyticsAPI = Mockito.mock(ContentAnalyticsAPI.class); + final AnalyticsQueryParser analyticsQueryParser = new AnalyticsQueryParser(); + final UserWebAPI userWebAPI = Mockito.mock(UserWebAPI.class); + final ViewContext viewContext = Mockito.mock(ViewContext.class); + final AnalyticsTool analyticsTool = new AnalyticsTool(contentAnalyticsAPI, + analyticsQueryParser, userWebAPI); + final User user = new User(); + + Mockito.when(viewContext.getRequest()).thenReturn(request); + Mockito.when(request.getSession(false)).thenReturn(session); + Mockito.when(userWebAPI.getLoggedInUser(request)).thenReturn(user); + + analyticsTool.init(viewContext); + analyticsTool.runReportFromJson(null); + } + + /** + * Method to test: {@link AnalyticsTool#runReportFromJson(String)} + * Given Scenario: Sending wrong as json + * ExpectedResult: Should throw IllegalArgumentException wrapped on DotRuntimeException + */ + @Test(expected = DotRuntimeException.class) + public void test_run_report_from_json_bad_json() { + + final HttpServletRequest request = Mockito.mock(HttpServletRequest.class); + final HttpSession session = Mockito.mock(HttpSession.class); + final ContentAnalyticsAPI contentAnalyticsAPI = Mockito.mock(ContentAnalyticsAPI.class); + final AnalyticsQueryParser analyticsQueryParser = new AnalyticsQueryParser(); + final UserWebAPI userWebAPI = Mockito.mock(UserWebAPI.class); + final ViewContext viewContext = Mockito.mock(ViewContext.class); + final AnalyticsTool analyticsTool = new AnalyticsTool(contentAnalyticsAPI, + analyticsQueryParser, userWebAPI); + final User user = new User(); + + Mockito.when(viewContext.getRequest()).thenReturn(request); + Mockito.when(request.getSession(false)).thenReturn(session); + Mockito.when(userWebAPI.getLoggedInUser(request)).thenReturn(user); + + analyticsTool.init(viewContext); + analyticsTool.runReportFromJson("{\n" + + "\t\"dimensions\": [\"Events.referer\", \"Events.experiment\", \"Events.variant\", \"Events.utcTime\", \"Events.url\", \"Events.lookBackWindow\", \"Events.eventType\"],\n" + + "\t\"measures\": [\"Events.count\", \"Events.uniqueCount\"],\n" + + "\t\"filters\": \"Events.variant = ['B'] or Events.experiments = ['B']\",\n" + + "\t\"limit\":100,\n" + + "\t\"offset\":1,\n" + + "\t\"timeDimensions\":Events.day day\",\n" + // here is a sintax error + "\t\"orders\":\"Events.day ASC\"\n" + + "}"); + } + + /** + * Method to test: {@link AnalyticsTool#runReportFromJson(String)} + * Given Scenario: Sending a good as json + * ExpectedResult: Should a non null ReportResponse + */ + @Test() + public void test_run_report_from_json_good_json() { + + final HttpServletRequest request = Mockito.mock(HttpServletRequest.class); + final HttpSession session = Mockito.mock(HttpSession.class); + final ContentAnalyticsAPI contentAnalyticsAPI = Mockito.mock(ContentAnalyticsAPI.class); + final AnalyticsQueryParser analyticsQueryParser = new AnalyticsQueryParser(); + final UserWebAPI userWebAPI = Mockito.mock(UserWebAPI.class); + final ViewContext viewContext = Mockito.mock(ViewContext.class); + final AnalyticsTool analyticsTool = new AnalyticsTool(contentAnalyticsAPI, + analyticsQueryParser, userWebAPI); + final User user = new User(); + + Mockito.when(viewContext.getRequest()).thenReturn(request); + Mockito.when(request.getSession(false)).thenReturn(session); + Mockito.when(userWebAPI.getLoggedInUser(request)).thenReturn(user); + Mockito.when(contentAnalyticsAPI.runReport(Mockito.any(), Mockito.eq(user))).thenReturn(new ReportResponse(List.of())); + + analyticsTool.init(viewContext); + final ReportResponse reportResponse = analyticsTool.runReportFromJson("{\n" + + "\t\"dimensions\": [\"Events.referer\", \"Events.experiment\", \"Events.variant\", \"Events.utcTime\", \"Events.url\", \"Events.lookBackWindow\", \"Events.eventType\"],\n" + + "\t\"measures\": [\"Events.count\", \"Events.uniqueCount\"],\n" + + "\t\"filters\": \"Events.variant = ['B'] or Events.experiments = ['B']\",\n" + + "\t\"limit\":100,\n" + + "\t\"offset\":1,\n" + + "\t\"timeDimensions\":\"Events.day day\",\n" + + "\t\"orders\":\"Events.day ASC\"\n" + + "}"); + + Assert.assertNotNull(reportResponse); + } + + /** + * Method to test: {@link AnalyticsTool#runReportFromMap(Map)} + * Given Scenario: Sending a null map + * ExpectedResult: Should throw {@link IllegalArgumentException} + */ + @Test(expected = IllegalArgumentException.class) + public void test_run_report_from_map_with_null_map() { + + final HttpServletRequest request = Mockito.mock(HttpServletRequest.class); + final HttpSession session = Mockito.mock(HttpSession.class); + final ContentAnalyticsAPI contentAnalyticsAPI = Mockito.mock(ContentAnalyticsAPI.class); + final AnalyticsQueryParser analyticsQueryParser = new AnalyticsQueryParser(); + final UserWebAPI userWebAPI = Mockito.mock(UserWebAPI.class); + final ViewContext viewContext = Mockito.mock(ViewContext.class); + final AnalyticsTool analyticsTool = new AnalyticsTool(contentAnalyticsAPI, + analyticsQueryParser, userWebAPI); + final User user = new User(); + + Mockito.when(viewContext.getRequest()).thenReturn(request); + Mockito.when(request.getSession(false)).thenReturn(session); + Mockito.when(userWebAPI.getLoggedInUser(request)).thenReturn(user); + Mockito.when(contentAnalyticsAPI.runReport(Mockito.any(), Mockito.eq(user))).thenReturn(new ReportResponse(List.of())); + + analyticsTool.init(viewContext); + final ReportResponse reportResponse = analyticsTool.runReportFromMap(null); + + Assert.assertNotNull(reportResponse); + } + + /** + * Method to test: {@link AnalyticsTool#runReportFromMap(Map)} + * Given Scenario: Sending a good as map + * ExpectedResult: Should a non null ReportResponse + */ + @Test() + public void test_run_report_from_map_good_map() { + + final HttpServletRequest request = Mockito.mock(HttpServletRequest.class); + final HttpSession session = Mockito.mock(HttpSession.class); + final ContentAnalyticsAPI contentAnalyticsAPI = Mockito.mock(ContentAnalyticsAPI.class); + final AnalyticsQueryParser analyticsQueryParser = new AnalyticsQueryParser(); + final UserWebAPI userWebAPI = Mockito.mock(UserWebAPI.class); + final ViewContext viewContext = Mockito.mock(ViewContext.class); + final AnalyticsTool analyticsTool = new AnalyticsTool(contentAnalyticsAPI, + analyticsQueryParser, userWebAPI); + final User user = new User(); + + Mockito.when(viewContext.getRequest()).thenReturn(request); + Mockito.when(request.getSession(false)).thenReturn(session); + Mockito.when(userWebAPI.getLoggedInUser(request)).thenReturn(user); + Mockito.when(contentAnalyticsAPI.runReport(Mockito.any(), Mockito.eq(user))).thenReturn(new ReportResponse(List.of())); + + analyticsTool.init(viewContext); + final Map queryMap = new HashMap<>(); + queryMap.put("dimensions", List.of("Events.referer", "Events.experiment", "Events.variant", "Events.utcTime", "Events.url", "Events.lookBackWindow", "Events.eventType")); + queryMap.put("measures", List.of("Events.count", "Events.uniqueCount")); + queryMap.put("filters", "Events.variant = ['B'] or Events.experiments = ['B']"); + queryMap.put("limit", 100); + queryMap.put("offset", 1); + queryMap.put("timeDimensions", "Events.day day"); + queryMap.put("orders", "Events.day ASC"); + final ReportResponse reportResponse = analyticsTool.runReportFromMap(queryMap); + + Assert.assertNotNull(reportResponse); + } + + /** + * Method to test: {@link AnalyticsTool#runRawReportFromJson(String)} + * Given Scenario: Sending a null json + * ExpectedResult: Should throw {@link IllegalArgumentException} + */ + @Test(expected = IllegalArgumentException.class) + public void test_run_raw_report_from_json_npe() { + + final HttpServletRequest request = Mockito.mock(HttpServletRequest.class); + final HttpSession session = Mockito.mock(HttpSession.class); + final ContentAnalyticsAPI contentAnalyticsAPI = Mockito.mock(ContentAnalyticsAPI.class); + final AnalyticsQueryParser analyticsQueryParser = new AnalyticsQueryParser(); + final UserWebAPI userWebAPI = Mockito.mock(UserWebAPI.class); + final ViewContext viewContext = Mockito.mock(ViewContext.class); + final AnalyticsTool analyticsTool = new AnalyticsTool(contentAnalyticsAPI, + analyticsQueryParser, userWebAPI); + final User user = new User(); + + Mockito.when(viewContext.getRequest()).thenReturn(request); + Mockito.when(request.getSession(false)).thenReturn(session); + Mockito.when(userWebAPI.getLoggedInUser(request)).thenReturn(user); + Mockito.when(contentAnalyticsAPI.runReport(Mockito.any(), Mockito.eq(user))).thenReturn(new ReportResponse(List.of())); + + analyticsTool.init(viewContext); + analyticsTool.runRawReport(null); + } + + /** + * Method to test: {@link AnalyticsTool#runRawReportFromJson(String)} + * Given Scenario: Sending a good json + * ExpectedResult: Should return not null ReportResponse + */ + @Test() + public void test_run_raw_report_from_json_good_job() { + + final HttpServletRequest request = Mockito.mock(HttpServletRequest.class); + final HttpSession session = Mockito.mock(HttpSession.class); + final ContentAnalyticsAPI contentAnalyticsAPI = Mockito.mock(ContentAnalyticsAPI.class); + final AnalyticsQueryParser analyticsQueryParser = new AnalyticsQueryParser(); + final UserWebAPI userWebAPI = Mockito.mock(UserWebAPI.class); + final ViewContext viewContext = Mockito.mock(ViewContext.class); + final AnalyticsTool analyticsTool = new AnalyticsTool(contentAnalyticsAPI, + analyticsQueryParser, userWebAPI); + final User user = new User(); + + Mockito.when(viewContext.getRequest()).thenReturn(request); + Mockito.when(request.getSession(false)).thenReturn(session); + Mockito.when(userWebAPI.getLoggedInUser(request)).thenReturn(user); + Mockito.when(contentAnalyticsAPI.runRawReport(Mockito.any(), Mockito.eq(user))).thenReturn(new ReportResponse(List.of())); + + analyticsTool.init(viewContext); + final CubeJSQuery.Builder builder = analyticsTool.createCubeJSQueryBuilder(); + builder.dimensions("Events.experiment", "Events.variant"); + final ReportResponse reportResponse = analyticsTool.runRawReport(builder.build()); + Assert.assertNotNull(reportResponse); + } +} diff --git a/tools/dotcms-cli/cli/src/test/java/com/dotcms/api/client/files/PushServiceIT.java b/tools/dotcms-cli/cli/src/test/java/com/dotcms/api/client/files/PushServiceIT.java index ba77c0e4a3f6..29325fb3995b 100644 --- a/tools/dotcms-cli/cli/src/test/java/com/dotcms/api/client/files/PushServiceIT.java +++ b/tools/dotcms-cli/cli/src/test/java/com/dotcms/api/client/files/PushServiceIT.java @@ -200,8 +200,7 @@ void Test_Nothing_To_Push() throws IOException { * * @throws IOException if an I/O error occurs */ - // Temporarily ignore this test until the root cause of the problem is found - //@Test + @Test void Test_Push_New_Site() throws IOException { // Create a temporal folder for the pull