diff --git a/.github/workflows/build_deploy_qa.yml b/.github/workflows/build_deploy_qa.yml index 267304162c..30fe31087c 100644 --- a/.github/workflows/build_deploy_qa.yml +++ b/.github/workflows/build_deploy_qa.yml @@ -11,10 +11,10 @@ on: # branches: [ master ] jobs: - build: + build: + name: build and deploy runs-on: ubuntu-latest - steps: - uses: actions/checkout@v2 - name: Set up JDK 11 @@ -22,8 +22,29 @@ jobs: with: java-version: '11' distribution: 'adopt' + cache: maven - name: Build with Maven run: | cd source - mvn -Dcerberus.delivery.username=${{secrets.CERBERUS_DELIVERY_USERNAME}} -Dcerberus.delivery.password=${{secrets.CERBERUS_DELIVERY_PASSWORD}} clean deploy -Pdelivery-deploy --file pom.xml - + mvn --batch-mode -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn clean install --file pom.xml + - name: Push file to core VM + env: + source-war: 'target/*.war' + source-zip: 'target/*.zip' + destination: 'debian@vm.cerberus-testing.org:/opt/delivery/' + run: | + cd source + echo "${{secrets.DEPLOY_KEY}}" > deploy_key + chmod 600 ./deploy_key + sudo rsync -chav \ + -e 'ssh -i ./deploy_key -o StrictHostKeyChecking=no' \ + ${{env.source-war}} ${{env.destination}} + sudo rsync -chav \ + -e 'ssh -i ./deploy_key -o StrictHostKeyChecking=no' \ + ${{env.source-zip}} ${{env.destination}} + - name: Deploy to QA + run: | + cd source + echo "${{secrets.DEPLOY_KEY}}" > deploy_key + chmod 600 ./deploy_key + ssh -i ./deploy_key -o StrictHostKeyChecking=no debian@vm.cerberus-testing.org "/opt/bin/deployQA.sh /opt/delivery/`find -type f -name cerberus-core*war | sed 's/.\/target\///g'`" diff --git a/.gitignore b/.gitignore index b9825cf5c8..9323aca1e8 100644 --- a/.gitignore +++ b/.gitignore @@ -28,4 +28,7 @@ docker/compositions/*/localdata/ # Chart dependencies **/helm/*.tgz *.tgz -.history \ No newline at end of file +.history + +# Temporary log files +hs_err_*.log diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..8f2b7113d2 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "java.compile.nullAnalysis.mode": "disabled" +} \ No newline at end of file diff --git a/README.md b/README.md index fbf497a9f6..52b87df4e9 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ Docker images are available for [MySQL](https://hub.docker.com/r/cerberustesting | --- | --- | | 🎤 Meetup | [Cerberus Testing User Group ](https://www.meetup.com/pt-BR/cerberus-testing-user-group/) | | 📺 Youtube | [Cerberus Testing Youtube Channel](https://www.youtube.com/channel/UCkG4csTjR0V5gl77BHhldBQ) | +| 🌎 CNLL Paris | [CNLL Paris Open Source Experience 2022: Special Jury Price](https://linuxfr.org/news/le-cnll-annonce-les-resultats-des-acteurs-du-libre-2022) | | 🌎 JFTL 2022 | [Implement Continuous Testing ](https://www.cftl.fr/jftl-22-implementer-le-continuous-testing-en-pratique/) | | 🌎 Sophia Open Source 2022 | [Continuous Testing in Action ](https://www.telecom-valley.fr/sophiaconf-2022/) | | 🌎 Sophia Open Source 2022 | [Cerberus Testing, 100% Open Source Test Automation ](https://www.youtube.com/watch?v=Zz0qG6iyd4g&list=PLupkTj3yDqODEnE0DaYkZ7F3osrnZHZQk&index=10) | diff --git a/docker/images/cerberus-as-tomcat-keycloak/4.16/Dockerfile b/docker/images/cerberus-as-tomcat-keycloak/4.16/Dockerfile new file mode 100644 index 0000000000..8ceea763f7 --- /dev/null +++ b/docker/images/cerberus-as-tomcat-keycloak/4.16/Dockerfile @@ -0,0 +1,68 @@ +FROM tomcat:8-jre8-alpine + +ENV LOG_ROOT_PATH /usr/local/tomcat/logs/ + +ENV KEYCLOACK_REALM Cerberus +ENV KEYCLOACK_CLIENT cerberus +ENV KEYCLOACK_URL http://192.168.1.1:8080/auth +ENV CATALINA_OPTS="-Dorg.cerberus.environment=prd -Dorg.cerberus.authentification=keycloak -Xmx1024m" +ENV KEYCLOACK_VERSION 8.0.2 +ENV KEYCLOACK_TOMCAT8_ADAPTER_NAME keycloak-tomcat-adapter-dist-${KEYCLOACK_VERSION} + +ENV DATABASE_HOST cerberus-db-mysql +ENV DATABASE_PORT 3306 +ENV DATABASE_NAME cerberus +ENV DATABASE_USER cerberus +ENV DATABASE_PASSWORD toto + +ARG CERBERUS_NAME=cerberus-core +ARG CERBERUS_VERSION=4.16 +ARG CERBERUS_PACKAGE_NAME=${CERBERUS_NAME}-${CERBERUS_VERSION} + +ARG MYSQL_JAVA_CONNECTOR_VERSION=5.1.47 +ARG MYSQL_JAVA_CONNECTOR_NAME=mysql-connector-java-${MYSQL_JAVA_CONNECTOR_VERSION} + +# Download and install MySQL JDBC Drivers +RUN echo "Download & install MySQL JDBC Drivers" && \ + wget -P /tmp/ https://downloads.mysql.com/archives/get/p/3/file/${MYSQL_JAVA_CONNECTOR_NAME}.zip && \ + unzip -q -d /tmp/ /tmp/${MYSQL_JAVA_CONNECTOR_NAME}.zip && \ + mv /tmp/${MYSQL_JAVA_CONNECTOR_NAME}/${MYSQL_JAVA_CONNECTOR_NAME}-bin.jar /usr/local/tomcat/lib/ && \ + echo "Clean temp directory" && \ + rm /tmp/* -rf +#COPY mysql-connector-java-5.1.20-bin.jar /usr/local/tomcat/lib/ + +# Only for debug purpose +#RUN ls -al /usr/local/tomcat/lib/ + +# Download & install KeyCloak adapter to manage authentification with Tomcat +RUN wget -P /tmp/ https://downloads.jboss.org/keycloak/${KEYCLOACK_VERSION}/adapters/keycloak-oidc/${KEYCLOACK_TOMCAT8_ADAPTER_NAME}.zip && \ + unzip -q -d /usr/local/tomcat/lib/ /tmp/${KEYCLOACK_TOMCAT8_ADAPTER_NAME}.zip && \ + echo "Clean temp directory" && \ + rm /tmp/* -rf +#COPY ${KEYCLOACK_TOMCAT8_ADAPTER_NAME}.zip /tmp/ + +# Only for debug purpose +#RUN ls -al /usr/local/tomcat/lib/ + +# Download & install Cerberus Application +RUN echo "Download & install Cerberus Application" && \ + wget -P /tmp/ https://github.com/cerberustesting/cerberus-source/releases/download/cerberus-testing-${CERBERUS_VERSION}/cerberus-core-${CERBERUS_VERSION}.zip && \ + unzip -q -d /tmp /tmp/${CERBERUS_PACKAGE_NAME}.zip && \ + rm -rf /usr/local/tomcat/webapps/* && \ + cp /tmp/${CERBERUS_PACKAGE_NAME}/${CERBERUS_PACKAGE_NAME}.war /usr/local/tomcat/webapps/ROOT.war && \ + echo "Clean temp directory" && \ + rm /tmp/* -rf +#COPY Cerberus-3.12-SNAPSHOT.war /usr/local/tomcat/webapps/ROOT.war + +# Only for debug purpose +#RUN ls -al /usr/local/tomcat/webapps/ + +# Configure Tomcat for Cerberus need. +COPY *.xml /usr/local/tomcat/conf/ + +# Only for debug purpose +#RUN echo ${CATALINA_OPTS} + +COPY entrypoint.sh /entrypoint.sh +RUN dos2unix /entrypoint.sh && chmod u+x /entrypoint.sh +ENTRYPOINT ["/entrypoint.sh"] diff --git a/docker/images/cerberus-as-tomcat-keycloak/4.16/context.xml b/docker/images/cerberus-as-tomcat-keycloak/4.16/context.xml new file mode 100644 index 0000000000..c2a16a1bbd --- /dev/null +++ b/docker/images/cerberus-as-tomcat-keycloak/4.16/context.xml @@ -0,0 +1,34 @@ + + + + + + + + WEB-INF/web.xml + ${catalina.base}/conf/web.xml + + + + + + diff --git a/docker/images/cerberus-as-tomcat-keycloak/4.16/entrypoint.sh b/docker/images/cerberus-as-tomcat-keycloak/4.16/entrypoint.sh new file mode 100644 index 0000000000..5cf856bf0e --- /dev/null +++ b/docker/images/cerberus-as-tomcat-keycloak/4.16/entrypoint.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# Cerberus Copyright (C) 2016 Cerberus Testing +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This file is part of Cerberus. +# +# Cerberus is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Cerberus is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Cerberus. If not, see . + +# Cerberus Tomcat configuration (with Keycloack acticated) + +export CATALINA_OPTS="$CATALINA_OPTS -DDATABASE_HOST=$DATABASE_HOST -DDATABASE_PORT=$DATABASE_PORT -DDATABASE_NAME=$DATABASE_NAME -DDATABASE_USER=$DATABASE_USER -DDATABASE_PASSWORD=$DATABASE_PASSWORD -Dorg.cerberus.authentification=keycloak -Dorg.cerberus.keycloak.realm=${KEYCLOAK_REALM} -Dorg.cerberus.keycloak.client=${KEYCLOAK_CLIENT} -Dorg.cerberus.keycloak.url=${KEYCLOAK_URL}" + +/usr/local/tomcat/bin/catalina.sh start + +tail -F /usr/local/tomcat/logs/catalina.out diff --git a/docker/images/cerberus-as-tomcat-keycloak/4.16/server.xml b/docker/images/cerberus-as-tomcat-keycloak/4.16/server.xml new file mode 100644 index 0000000000..4489cb19eb --- /dev/null +++ b/docker/images/cerberus-as-tomcat-keycloak/4.16/server.xml @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docker/images/cerberus-as-tomcat-keycloak/README.md b/docker/images/cerberus-as-tomcat-keycloak/README.md index 981b8d4cf8..c06c22c173 100644 --- a/docker/images/cerberus-as-tomcat-keycloak/README.md +++ b/docker/images/cerberus-as-tomcat-keycloak/README.md @@ -11,6 +11,7 @@ Hereafter list of available tags: Tag | Description | Source --------|------------------------------------|------------------------------- latest | Use the latest Cerberus version | [latest/Dockerfile](https://github.com/cerberustesting/cerberus-source/blob/master/docker/images/cerberus-as-tomcat-keycloak/latest/Dockerfile) +4.16 | Use the 4.16 Cerberus version | [4.16/Dockerfile](https://github.com/cerberustesting/cerberus-source/blob/master/docker/images/cerberus-as-tomcat-keycloak/4.16/Dockerfile) 4.15 | Use the 4.15 Cerberus version | [4.15/Dockerfile](https://github.com/cerberustesting/cerberus-source/blob/master/docker/images/cerberus-as-tomcat-keycloak/4.15/Dockerfile) 4.14 | Use the 4.14 Cerberus version | [4.14/Dockerfile](https://github.com/cerberustesting/cerberus-source/blob/master/docker/images/cerberus-as-tomcat-keycloak/4.14/Dockerfile) 4.13.1 | Use the 4.13.1 Cerberus version | [4.13.1/Dockerfile](https://github.com/cerberustesting/cerberus-source/blob/master/docker/images/cerberus-as-tomcat-keycloak/4.13.1/Dockerfile) diff --git a/docker/images/cerberus-as-tomcat-keycloak/latest/Dockerfile b/docker/images/cerberus-as-tomcat-keycloak/latest/Dockerfile index d7a82bb068..8ceea763f7 100644 --- a/docker/images/cerberus-as-tomcat-keycloak/latest/Dockerfile +++ b/docker/images/cerberus-as-tomcat-keycloak/latest/Dockerfile @@ -16,7 +16,7 @@ ENV DATABASE_USER cerberus ENV DATABASE_PASSWORD toto ARG CERBERUS_NAME=cerberus-core -ARG CERBERUS_VERSION=4.15 +ARG CERBERUS_VERSION=4.16 ARG CERBERUS_PACKAGE_NAME=${CERBERUS_NAME}-${CERBERUS_VERSION} ARG MYSQL_JAVA_CONNECTOR_VERSION=5.1.47 diff --git a/docker/images/cerberus-as-tomcat/4.16/Dockerfile b/docker/images/cerberus-as-tomcat/4.16/Dockerfile new file mode 100644 index 0000000000..9e7bf98de3 --- /dev/null +++ b/docker/images/cerberus-as-tomcat/4.16/Dockerfile @@ -0,0 +1,53 @@ +FROM tomcat:8-jre8-alpine + +ENV LOG_ROOT_PATH /usr/local/tomcat/logs/ + +ENV CATALINA_OPTS="-Dorg.cerberus.environment=prd -Dorg.cerberus.authentification=none -Xmx1024m" + +ENV DATABASE_HOST cerberus-db-mysql +ENV DATABASE_PORT 3306 +ENV DATABASE_NAME cerberus +ENV DATABASE_USER cerberus +ENV DATABASE_PASSWORD toto + +ARG CERBERUS_NAME=cerberus-core +ARG CERBERUS_VERSION=4.16 +ARG CERBERUS_PACKAGE_NAME=${CERBERUS_NAME}-${CERBERUS_VERSION} + +ARG MYSQL_JAVA_CONNECTOR_VERSION=5.1.47 +ARG MYSQL_JAVA_CONNECTOR_NAME=mysql-connector-java-${MYSQL_JAVA_CONNECTOR_VERSION} + +# Download & install MySQL JDBC Drivers +RUN echo "Download & install MySQL JDBC Drivers" && \ + wget -P /tmp/ https://downloads.mysql.com/archives/get/p/3/file/${MYSQL_JAVA_CONNECTOR_NAME}.zip && \ + unzip -q -d /tmp/ /tmp/${MYSQL_JAVA_CONNECTOR_NAME}.zip && \ + mv /tmp/${MYSQL_JAVA_CONNECTOR_NAME}/${MYSQL_JAVA_CONNECTOR_NAME}-bin.jar /usr/local/tomcat/lib/ && \ + echo "Clean temp directory" && \ + rm /tmp/* -rf +#COPY mysql-connector-java-5.1.20-bin.jar /usr/local/tomcat/lib/ + +# Only for debug purpose +#RUN ls -al /usr/local/tomcat/lib/ + +# Download & install Cerberus Application +RUN echo "Download & install Cerberus Application" && \ + wget -P /tmp/ https://github.com/cerberustesting/cerberus-source/releases/download/cerberus-testing-${CERBERUS_VERSION}/cerberus-core-${CERBERUS_VERSION}.zip && \ + unzip -q -d /tmp /tmp/${CERBERUS_PACKAGE_NAME}.zip && \ + rm -rf /usr/local/tomcat/webapps/* && \ + cp /tmp/${CERBERUS_PACKAGE_NAME}/${CERBERUS_PACKAGE_NAME}.war /usr/local/tomcat/webapps/ROOT.war && \ + echo "Clean temp directory" && \ + rm /tmp/* -rf +#COPY Cerberus-3.12-SNAPSHOT.war /usr/local/tomcat/webapps/ROOT.war + +# Only for debug purpose +#RUN ls -al /usr/local/tomcat/webapps/ + +# Configure Tomcat for Cerberus need. +COPY *.xml /usr/local/tomcat/conf/ + +# Only for debug purpose +#RUN echo ${CATALINA_OPTS} + +COPY entrypoint.sh /entrypoint.sh +RUN dos2unix /entrypoint.sh && chmod u+x /entrypoint.sh +ENTRYPOINT ["/entrypoint.sh"] diff --git a/docker/images/cerberus-as-tomcat/4.16/context.xml b/docker/images/cerberus-as-tomcat/4.16/context.xml new file mode 100644 index 0000000000..5a70b23718 --- /dev/null +++ b/docker/images/cerberus-as-tomcat/4.16/context.xml @@ -0,0 +1,37 @@ + + + + + + + + WEB-INF/web.xml + ${catalina.base}/conf/web.xml + + + + + + + + + diff --git a/docker/images/cerberus-as-tomcat/4.16/entrypoint.sh b/docker/images/cerberus-as-tomcat/4.16/entrypoint.sh new file mode 100644 index 0000000000..dd5b5f49f4 --- /dev/null +++ b/docker/images/cerberus-as-tomcat/4.16/entrypoint.sh @@ -0,0 +1,32 @@ +#!/bin/bash +# Cerberus Copyright (C) 2016 Cerberus Testing +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This file is part of Cerberus. +# +# Cerberus is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Cerberus is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Cerberus. If not, see . + +# Cerberus Glassfish configuration + + +# test add realm + + +# export CATALINA_OPTS="$CATALINA_OPTS -DDATABASE_HOST=$DATABASE_HOST -DDATABASE_PORT=$DATABASE_PORT -DDATABASE_NAME=$DATABASE_NAME -DDATABASE_USER=$DATABASE_USER -DDATABASE_PASSWORD=$DATABASE_PASSWORD" + +export CATALINA_OPTS="$CATALINA_OPTS -DDATABASE_HOST=$DATABASE_HOST -DDATABASE_PORT=$DATABASE_PORT -DDATABASE_NAME=$DATABASE_NAME -DDATABASE_USER=$DATABASE_USER -DDATABASE_PASSWORD=$DATABASE_PASSWORD" + +/usr/local/tomcat/bin/catalina.sh start + +tail -F /usr/local/tomcat/logs/catalina.out diff --git a/docker/images/cerberus-as-tomcat/4.16/server.xml b/docker/images/cerberus-as-tomcat/4.16/server.xml new file mode 100644 index 0000000000..2cc1c85fca --- /dev/null +++ b/docker/images/cerberus-as-tomcat/4.16/server.xml @@ -0,0 +1,188 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docker/images/cerberus-as-tomcat/README.md b/docker/images/cerberus-as-tomcat/README.md index ad29151b83..985d9e6fd3 100644 --- a/docker/images/cerberus-as-tomcat/README.md +++ b/docker/images/cerberus-as-tomcat/README.md @@ -11,6 +11,7 @@ Hereafter list of available tags: Tag | Description | Source --------|------------------------------------|------------------------------- latest | Use the latest Cerberus version | [latest/Dockerfile](https://github.com/cerberustesting/cerberus-source/blob/master/docker/images/cerberus-as-tomcat/latest/Dockerfile) +4.16 | Use the 4.16 Cerberus version | [4.16/Dockerfile](https://github.com/cerberustesting/cerberus-source/blob/master/docker/images/cerberus-as-tomcat/4.16/Dockerfile) 4.15 | Use the 4.15 Cerberus version | [4.15/Dockerfile](https://github.com/cerberustesting/cerberus-source/blob/master/docker/images/cerberus-as-tomcat/4.15/Dockerfile) 4.14 | Use the 4.14 Cerberus version | [4.14/Dockerfile](https://github.com/cerberustesting/cerberus-source/blob/master/docker/images/cerberus-as-tomcat/4.14/Dockerfile) 4.13.1 | Use the 4.13.1 Cerberus version | [4.13.1/Dockerfile](https://github.com/cerberustesting/cerberus-source/blob/master/docker/images/cerberus-as-tomcat/4.13.1/Dockerfile) diff --git a/docker/images/cerberus-as-tomcat/latest/Dockerfile b/docker/images/cerberus-as-tomcat/latest/Dockerfile index 23ff078b15..9e7bf98de3 100644 --- a/docker/images/cerberus-as-tomcat/latest/Dockerfile +++ b/docker/images/cerberus-as-tomcat/latest/Dockerfile @@ -11,7 +11,7 @@ ENV DATABASE_USER cerberus ENV DATABASE_PASSWORD toto ARG CERBERUS_NAME=cerberus-core -ARG CERBERUS_VERSION=4.15 +ARG CERBERUS_VERSION=4.16 ARG CERBERUS_PACKAGE_NAME=${CERBERUS_NAME}-${CERBERUS_VERSION} ARG MYSQL_JAVA_CONNECTOR_VERSION=5.1.47 diff --git a/pom.xml b/pom.xml index e72510dad0..d6ebc62c96 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ org.cerberus cerberus-testing - 4.16-SNAPSHOT + 4.17-SNAPSHOT pom Cerberus Core Master diff --git a/source/.gitignore b/source/.gitignore index a98af29985..c123e16e1c 100644 --- a/source/.gitignore +++ b/source/.gitignore @@ -2,6 +2,7 @@ target/ .classpath .settings .project +*.log /src/main/webapp/documentation/ localdata nb-configuration.xml diff --git a/source/pom.xml b/source/pom.xml index 27a00a1b2a..a7f017b1e6 100644 --- a/source/pom.xml +++ b/source/pom.xml @@ -25,7 +25,7 @@ org.cerberus cerberus-core - 4.16-SNAPSHOT + 4.17-SNAPSHOT war Cerberus Core @@ -40,7 +40,7 @@ 5.3.20 - 5.6.9 + 5.6.12 20080701 2.9.0 @@ -71,9 +71,9 @@ 1.5 20211018.1 1.0.16 - 1.3.3 + 1.5 2.7 - 3.6 + 3.9.0 3.12.0 4.4 0.8.5 @@ -93,6 +93,8 @@ 2.3.0 6.2.1 + + 4.9.1 1.18.22 0.2.0 @@ -123,6 +125,9 @@ 1.6.0 2.0 + + 8.0.1 + src/main/webapp/dependencies/Ace-1.2.6/worker-xquery.js @@ -320,6 +325,14 @@ ${kafka-avro-serializer.version} compile + + + + org.mongodb + mongodb-driver-sync + ${mongodb-driver-sync.version} + + org.jboss.aerogear @@ -497,6 +510,57 @@ ${springfox.version} + + + com.itextpdf + kernel + ${com.itextpdf.version} + + + com.itextpdf + io + ${com.itextpdf.version} + + + com.itextpdf + layout + ${com.itextpdf.version} + + + com.itextpdf + forms + ${com.itextpdf.version} + + + com.itextpdf + pdfa + ${com.itextpdf.version} + + + com.itextpdf + sign + ${com.itextpdf.version} + + + com.itextpdf + barcodes + ${com.itextpdf.version} + + + com.itextpdf + font-asian + ${com.itextpdf.version} + + + com.itextpdf + hyph + ${com.itextpdf.version} + + + com.itextpdf + html2pdf + 5.0.0 + we stop here with decode message in the action result. + actionExecution.setActionResultMessage(answerDecode.getResultMessage().resolveDescription("FIELD", "Action Value3")); + actionExecution.setExecutionResultMessage(new MessageGeneral(answerDecode.getResultMessage().getMessage())); + actionExecution.setStopExecution(answerDecode.getResultMessage().isStopTest()); + actionExecution.setEnd(new Date().getTime()); + LOG.debug("Action interupted due to decode 'Action Value3' Error."); + return actionExecution; + } + } catch (CerberusEventException cex) { + actionExecution.setActionResultMessage(cex.getMessageError()); + actionExecution.setExecutionResultMessage(new MessageGeneral(cex.getMessageError().getMessage())); + actionExecution.setEnd(new Date().getTime()); + return actionExecution; + } + /** * Timestamp starts after the decode. */ @@ -323,6 +339,9 @@ public TestCaseStepActionExecution doAction(TestCaseStepActionExecution actionEx case TestCaseStepAction.ACTION_SWITCHTOWINDOW: res = this.doActionSwitchToWindow(execution, value1, value2); break; + case TestCaseStepAction.ACTION_SWITCHTOCONTEXT: + res = this.doActionSwitchToContext(execution, value1); + break; case TestCaseStepAction.ACTION_MANAGEDIALOG: res = this.doActionManageDialog(execution, value1, value2); break; @@ -544,7 +563,7 @@ private MessageEvent doActionGetRobotFile(TestCaseExecution execution, TestCaseS } LOG.debug(contentJSON.toString(1)); - AppService appSrv = factoryAppService.create("", "", "", "", "", "", "", "", "", "", "", "", "", "", false, "", "", false, "", "", "", "", null, "", null, ""); + AppService appSrv = factoryAppService.create("", "", "", "", "", "", "", "", "", "", "", "", "", "", false, "", "", false, "", false, "", false, "", "", "", null, "", null, ""); JSONObject contentJSONnew = new JSONObject(); // We copy the header values for the service answered. @@ -740,7 +759,10 @@ private MessageEvent doActionScrollTo(TestCaseExecution tCExecution, String elem return message; } catch (Exception e) { message = new MessageEvent(MessageEventEnum.ACTION_FAILED_GENERIC); - String messageString = e.getMessage().split("\n")[0]; + String messageString = ""; + if (e.getMessage() != null) { + messageString = e.getMessage().split("\n")[0]; + } message.setDescription(message.getDescription().replace("%DETAIL%", messageString)); LOG.debug("Exception Running scroll to :" + messageString, e); return message; @@ -1021,6 +1043,19 @@ private MessageEvent doActionSwitchToWindow(TestCaseExecution tCExecution, Strin } } + private MessageEvent doActionSwitchToContext(TestCaseExecution tCExecution, String context) { + String applicationType = tCExecution.getApplicationObj().getType(); + if (applicationType.equalsIgnoreCase(Application.TYPE_APK)) { + return androidAppiumService.switchToContext(tCExecution.getSession(), context); + } else if (applicationType.equalsIgnoreCase(Application.TYPE_IPA)) { + return iosAppiumService.switchToContext(tCExecution.getSession(), context); + } else { + return new MessageEvent(MessageEventEnum.ACTION_NOTEXECUTED_NOTSUPPORTED_FOR_APPLICATION) + .resolveDescription("ACTION", "SwitchToContext") + .resolveDescription("APPLICATIONTYPE", tCExecution.getApplicationObj().getType()); + } + } + private MessageEvent doActionManageDialog(TestCaseExecution tCExecution, String value1, String value2) { MessageEvent message; String element; @@ -1667,13 +1702,13 @@ public MessageEvent doActionDragAndDrop(TestCaseExecution tCExecution, String va } } - private MessageEvent doActionCallService(TestCaseStepActionExecution testCaseStepActionExecution, String value1, String value2, String value3) { + private MessageEvent doActionCallService(TestCaseStepActionExecution action, String value1, String value2, String value3) { MessageEvent message = new MessageEvent(MessageEventEnum.ACTION_FAILED_CALLSERVICE); - TestCaseExecution tCExecution = testCaseStepActionExecution.getTestCaseStepExecution().gettCExecution(); + TestCaseExecution tCExecution = action.getTestCaseStepExecution().gettCExecution(); AnswerItem lastServiceCalledAnswer; - lastServiceCalledAnswer = serviceService.callService(value1, value2, value3, null, null, null, null, tCExecution); + lastServiceCalledAnswer = serviceService.callService(value1, value2, value3, null, null, null, null, tCExecution, robotServerService.getFromOptions(action.getOptions(), RobotServerService.OPTIONS_TIMEOUT_SYNTAX)); message = lastServiceCalledAnswer.getResultMessage(); if (lastServiceCalledAnswer.getItem() != null) { @@ -1685,7 +1720,7 @@ private MessageEvent doActionCallService(TestCaseStepActionExecution testCaseSte /** * Record the Request and Response in file system. */ - testCaseStepActionExecution.addFileList(recorderService.recordServiceCall(tCExecution, testCaseStepActionExecution, 0, null, lastServiceCalled)); + action.addFileList(recorderService.recordServiceCall(tCExecution, action, 0, null, lastServiceCalled)); } return message; @@ -1871,7 +1906,7 @@ private MessageEvent doActionSetNetworkTrafficContent(TestCaseExecution exe, Tes har = harService.enrichWithStats(har, exe.getCountryEnvironmentParameters().getDomain(), exe.getSystem(), exe.getNetworkTrafficIndexList()); - AppService appSrv = factoryAppService.create("", AppService.TYPE_REST, AppService.METHOD_HTTPGET, "", "", "", "", "", "", "", "", "", "", "", true, "", "", false, "", "", "", "", null, "", null, null); + AppService appSrv = factoryAppService.create("", AppService.TYPE_REST, AppService.METHOD_HTTPGET, "", "", "", "", "", "", "", "", "", "", "", true, "", "", false, "", false, "", false, "", "", "", null, "", null, null); appSrv.setResponseHTTPBody(har.toString()); appSrv.setResponseHTTPBodyContentType(AppService.RESPONSEHTTPBODYCONTENTTYPE_JSON); appSrv.setRecordTraceFile(false); @@ -1952,7 +1987,7 @@ private MessageEvent doActionSetConsoleContent(TestCaseExecution exe, TestCaseSt consoleStat = consolelogService.enrichWithStats(consoleLogs); consoleRecap.put("stat", consoleStat); - AppService appSrv = factoryAppService.create("", "", "", "", "", "", "", "", "", "", "", "", "", "", false, "", "", false, "", "", null, "", null, "", null, ""); + AppService appSrv = factoryAppService.create("", "", "", "", "", "", "", "", "", "", "", "", "", "", false, "", "", false, "", false, "", false, "", null, "", null, "", null, ""); appSrv.setResponseHTTPBody(consoleRecap.toString()); appSrv.setResponseHTTPBodyContentType(AppService.RESPONSEHTTPBODYCONTENTTYPE_JSON); appSrv.setRecordTraceFile(false); @@ -1985,7 +2020,7 @@ private MessageEvent doActionSetContent(TestCaseExecution exe, TestCaseStepActio */ LOG.debug("Setting static content."); - AppService appSrv = factoryAppService.create("", "", "", "", "", "", "", "", "", "", "", "", "", "", false, "", "", false, "", "", "", "", null, "", null, ""); + AppService appSrv = factoryAppService.create("", "", "", "", "", "", "", "", "", "", "", "", "", "", false, "", "", false, "", false, "", false, "", "", "", null, "", null, ""); appSrv.setResponseHTTPBody(textContent); appSrv.setResponseHTTPBodyContentType(appServiceService.guessContentType(appSrv, AppService.RESPONSEHTTPBODYCONTENTTYPE_JSON)); appSrv.setRecordTraceFile(false); diff --git a/source/src/main/java/org/cerberus/core/engine/gwt/impl/ControlService.java b/source/src/main/java/org/cerberus/core/engine/gwt/impl/ControlService.java index 1f69cce5dd..111837e183 100644 --- a/source/src/main/java/org/cerberus/core/engine/gwt/impl/ControlService.java +++ b/source/src/main/java/org/cerberus/core/engine/gwt/impl/ControlService.java @@ -308,6 +308,12 @@ public TestCaseStepActionControlExecution doControl(TestCaseStepActionControlExe case TestCaseStepActionControl.CONTROL_VERIFYELEMENTNOTVISIBLE: res = this.verifyElementNotVisible(execution, value1); break; + case TestCaseStepActionControl.CONTROL_VERIFYELEMENTCHECKED: + res = this.verifyElementChecked(execution, value1); + break; + case TestCaseStepActionControl.CONTROL_VERIFYELEMENTNOTCHECKED: + res = this.verifyElementNotChecked(execution, value1); + break; case TestCaseStepActionControl.CONTROL_VERIFYELEMENTEQUALS: res = this.verifyElementEquals(execution, value1, controlExecution.getValue2()); break; @@ -914,6 +920,66 @@ private MessageEvent verifyElementNotVisible(TestCaseExecution tCExecution, Stri return mes; } + private MessageEvent verifyElementChecked(TestCaseExecution tCExecution, String html) { + LOG.debug("Control: verifyElementChecked on: {}", html); + MessageEvent mes; + if (!StringUtil.isEmptyOrNullValue(html)) { + if (tCExecution.getAppTypeEngine().equalsIgnoreCase(Application.TYPE_GUI) + || tCExecution.getAppTypeEngine().equalsIgnoreCase(Application.TYPE_APK) + || tCExecution.getAppTypeEngine().equalsIgnoreCase(Application.TYPE_IPA)) { + + try { + Identifier identifier = identifierService.convertStringToIdentifier(html); + if (this.webdriverService.isElementChecked(tCExecution.getSession(), identifier)) { + mes = new MessageEvent(MessageEventEnum.CONTROL_SUCCESS_CHECKED); + } else { + mes = new MessageEvent(MessageEventEnum.CONTROL_FAILED_CHECKED); + } + mes.resolveDescription("STRING1", html); + } catch (WebDriverException exception) { + return parseWebDriverException(exception); + } + } else { + mes = new MessageEvent(MessageEventEnum.CONTROL_NOTEXECUTED_NOTSUPPORTED_FOR_APPLICATION); + mes.resolveDescription("CONTROL", TestCaseStepActionControl.CONTROL_VERIFYELEMENTCHECKED); + mes.resolveDescription("APPLICATIONTYPE", tCExecution.getAppTypeEngine()); + } + } else { + mes = new MessageEvent(MessageEventEnum.CONTROL_FAILED_CHECKED_NULL); + } + return mes; + } + + private MessageEvent verifyElementNotChecked(TestCaseExecution tCExecution, String html) { + LOG.debug("Control: verifyElementNotChecked on: {}", html); + MessageEvent mes; + if (!StringUtil.isEmptyOrNullValue(html)) { + if (tCExecution.getAppTypeEngine().equalsIgnoreCase(Application.TYPE_GUI) + || tCExecution.getAppTypeEngine().equalsIgnoreCase(Application.TYPE_APK) + || tCExecution.getAppTypeEngine().equalsIgnoreCase(Application.TYPE_IPA)) { + + try { + Identifier identifier = identifierService.convertStringToIdentifier(html); + if (this.webdriverService.isElementNotChecked(tCExecution.getSession(), identifier)) { + mes = new MessageEvent(MessageEventEnum.CONTROL_SUCCESS_NOTCHECKED); + } else { + mes = new MessageEvent(MessageEventEnum.CONTROL_FAILED_NOTCHECKED); + } + mes.resolveDescription("STRING1", html); + } catch (WebDriverException exception) { + return parseWebDriverException(exception); + } + } else { + mes = new MessageEvent(MessageEventEnum.CONTROL_NOTEXECUTED_NOTSUPPORTED_FOR_APPLICATION); + mes.resolveDescription("CONTROL", TestCaseStepActionControl.CONTROL_VERIFYELEMENTNOTCHECKED); + mes.resolveDescription("APPLICATIONTYPE", tCExecution.getAppTypeEngine()); + } + } else { + mes = new MessageEvent(MessageEventEnum.CONTROL_FAILED_NOTCHECKED_NULL); + } + return mes; + } + private MessageEvent verifyElementEquals(TestCaseExecution tCExecution, String xpath, String expectedElement) { LOG.debug("Control: verifyElementEquals on: {} expected Element: {}", xpath, expectedElement); MessageEvent mes; @@ -1219,13 +1285,13 @@ private MessageEvent verifyElementTextMatchRegex(TestCaseExecution tCExecution, case AppService.RESPONSEHTTPBODYCONTENTTYPE_JSON: try { - pathContent = jsonService.getFromJson(responseBody, null, path); - } catch (Exception ex) { - mes = new MessageEvent(MessageEventEnum.CONTROL_FAILED_GENERIC); - mes.resolveDescription("ERROR", ex.toString()); - return mes; - } - break; + pathContent = jsonService.getFromJson(responseBody, null, path); + } catch (Exception ex) { + mes = new MessageEvent(MessageEventEnum.CONTROL_FAILED_GENERIC); + mes.resolveDescription("ERROR", ex.toString()); + return mes; + } + break; default: mes = new MessageEvent(MessageEventEnum.CONTROL_NOTEXECUTED_NOTSUPPORTED_FOR_MESSAGETYPE); diff --git a/source/src/main/java/org/cerberus/core/engine/queuemanagement/impl/ExecutionQueueWorkerThread.java b/source/src/main/java/org/cerberus/core/engine/queuemanagement/impl/ExecutionQueueWorkerThread.java index 8b0e7ec473..e4062e4d3b 100644 --- a/source/src/main/java/org/cerberus/core/engine/queuemanagement/impl/ExecutionQueueWorkerThread.java +++ b/source/src/main/java/org/cerberus/core/engine/queuemanagement/impl/ExecutionQueueWorkerThread.java @@ -406,9 +406,9 @@ private void runParseAnswer(String answer, String cerberusUrl, String cerberusFu // Check answer format Matcher matcher = EXECUTION_ID_FROM_ANSWER_PATTERN.matcher(answer); if (!matcher.find()) { - LOG.error("Bad answer format (could not find 'RunID = '). URL Called: " + cerberusFullUrl); - LOG.error("Bad answer format (could not find 'RunID = '). Answer: " + answer); - throw new RunQueueProcessException("Error occured when calling the service to run the testcase. Service answer did not have the expected format (missing 'RunID = '). Probably due to bad cerberus_url value. URL Called: '" + cerberusUrl + "'."); + LOG.error("Bad answer format (could not find 'id = '). URL Called: " + cerberusFullUrl); + LOG.error("Bad answer format (could not find 'id = '). Answer: " + answer); + throw new RunQueueProcessException("Error occured when calling the service to run the testcase. Service answer did not have the expected format (missing 'id = '). Probably due to bad cerberus_url value. URL Called: '" + cerberusUrl + "'."); } // Extract the return code @@ -424,9 +424,9 @@ private void runParseAnswer(String answer, String cerberusUrl, String cerberusFu if (executionID == 0) { Matcher descriptionMatcher = RETURN_CODE_DESCRIPTION_FROM_ANSWER_PATTERN.matcher(answer); if (!descriptionMatcher.find()) { - LOG.error("Bad answer format (could not find 'ReturnCodeDescription = '). URL Called: " + cerberusFullUrl); - LOG.error("Bad answer format (could not find 'ReturnCodeDescription = '). Answer: " + answer); - throw new RunQueueProcessException("Error occured when calling the service to run the testcase. Service answer did not have the expected format (missing 'ReturnCodeDescription = '). Probably due to bad cerberus_url value. URL Called: '" + cerberusUrl + "'."); + LOG.error("Bad answer format (could not find 'controlMessage = '). URL Called: " + cerberusFullUrl); + LOG.error("Bad answer format (could not find 'controlMessage = '). Answer: " + answer); + throw new RunQueueProcessException("Error occured when calling the service to run the testcase. Service answer did not have the expected format (missing 'controlMessage = '). Probably due to bad cerberus_url value. URL Called: '" + cerberusUrl + "'."); } throw new RunQueueProcessException(descriptionMatcher.group(1)); } diff --git a/source/src/main/java/org/cerberus/core/enums/MessageEventEnum.java b/source/src/main/java/org/cerberus/core/enums/MessageEventEnum.java index 8ba73e55c6..2ec76c071e 100644 --- a/source/src/main/java/org/cerberus/core/enums/MessageEventEnum.java +++ b/source/src/main/java/org/cerberus/core/enums/MessageEventEnum.java @@ -205,6 +205,7 @@ public enum MessageEventEnum { ACTION_SUCCESS_MOUSEDOWN(200, "OK", "Mouse Left Click pressed on Element '%ELEMENT%'.", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), ACTION_SUCCESS_MOUSEUP(200, "OK", "Mouse Left Click Released on Element '%ELEMENT%'.", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), ACTION_SUCCESS_SWITCHTOWINDOW(200, "OK", "Focus of Selenium was changed to Window '%WINDOW%'", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), + ACTION_SUCCESS_SWITCHTOCONTEXT(200, "OK", "Context was successfully changed to %CONTEXT%.", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), ACTION_SUCCESS_CLOSE_ALERT(200, "OK", "Alert popup is closed !", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), ACTION_SUCCESS_KEYPRESS_ALERT(200, "OK", "Keypress '%KEY%' done on alert popup !", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), ACTION_SUCCESS_CALLSOAP(200, "OK", "Call to SOAP Operation '%SOAPMETHOD%' on Service Path %SERVICEPATH% executed successfully and stored to memory!", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), @@ -294,6 +295,7 @@ public enum MessageEventEnum { ACTION_FAILED_MOUSEUP_NO_SUCH_ELEMENT(282, "FA", "Failed to release click because could not find element '%ELEMENT%'!", true, true, true, MessageGeneralEnum.EXECUTION_FA_ACTION), ACTION_FAILED_MOUSEDOWN_NO_SUCH_ELEMENT(283, "FA", "Failed to left click because could not find element '%ELEMENT%'!", true, true, true, MessageGeneralEnum.EXECUTION_FA_ACTION), ACTION_FAILED_SWITCHTOWINDOW_NO_SUCH_ELEMENT(280, "FA", "Failed to switch to window because could not find element '%WINDOW%'!", true, true, true, MessageGeneralEnum.EXECUTION_FA_ACTION), + ACTION_FAILED_SWITCHTOCONTEXT_NO_SUCH_ELEMENT(280, "FA", "Failed to switch to context '%CONTEXT%' because could not find it! Available contexts are: '%CONTEXTS%'. Detailed error: %ERROR%", true, true, true, MessageGeneralEnum.EXECUTION_FA_ACTION), ACTION_FAILED_CLOSE_ALERT(280, "FA", "Failed to close the alert popup ! Please either specify 'ok' or 'cancel'.", true, true, true, MessageGeneralEnum.EXECUTION_FA_ACTION), ACTION_FAILED_KEYPRESS_ALERT(280, "FA", "Failed to keypress '%KEY%' on the alert popup !", true, true, true, MessageGeneralEnum.EXECUTION_FA_ACTION), ACTION_FAILED_CALLSERVICE_SEEKALLTOPICS(286, "FA", "Failed when getting latest offset of every topics. %DESCRIPTION%.", true, true, false, MessageGeneralEnum.EXECUTION_FA_ACTION), @@ -370,6 +372,8 @@ public enum MessageEventEnum { CONTROL_SUCCESS_NOTPRESENT(300, "OK", "Element '%STRING1%' is not present on the message/page/screen.", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), CONTROL_SUCCESS_VISIBLE(300, "OK", "Element '%STRING1%' is visible on the page.", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), CONTROL_SUCCESS_NOTVISIBLE(300, "OK", "Element '%STRING1%' is present and not visible on the page.", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), + CONTROL_SUCCESS_CHECKED(300, "OK", "Element '%STRING1%' is checked.", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), + CONTROL_SUCCESS_NOTCHECKED(300, "OK", "Element '%STRING1%' is not checked.", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), CONTROL_SUCCESS_ELEMENTTEXTEQUAL(300, "OK", "Element '%ELEMENT%' with value '%ELEMENTVALUE%' is equal to %VALUE% (%CASESENSITIVE%).", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), CONTROL_SUCCESS_ELEMENTTEXTDIFFERENT(300, "OK", "Element '%ELEMENT%' with value '%ELEMENTVALUE%' is different than %VALUE% (%CASESENSITIVE%).", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), CONTROL_SUCCESS_ELEMENTTEXTCONTAINS(300, "OK", "Element '%ELEMENT%' with value '%ELEMENTVALUE%' contains '%VALUE%' (%CASESENSITIVE%).", false, false, false, MessageGeneralEnum.EXECUTION_PE_TESTSTARTED), @@ -418,8 +422,12 @@ public enum MessageEventEnum { CONTROL_FAILED_NOTPRESENT_NULL(364, "KO", "Value1 is 'null'. This is mandatory in order to perform the control verify element not present", true, false, true, MessageGeneralEnum.EXECUTION_KO), CONTROL_FAILED_VISIBLE(365, "KO", "Element '%STRING1%' not visible on the page.", true, true, true, MessageGeneralEnum.EXECUTION_KO), CONTROL_FAILED_NOTVISIBLE(365, "KO", "Element '%STRING1%' is visible on the page.", true, true, true, MessageGeneralEnum.EXECUTION_KO), + CONTROL_FAILED_CHECKED(365, "KO", "Element '%STRING1%' is detected as not checked.", true, true, true, MessageGeneralEnum.EXECUTION_KO), + CONTROL_FAILED_NOTCHECKED(365, "KO", "Element '%STRING1%' is detected as checked.", true, true, true, MessageGeneralEnum.EXECUTION_KO), CONTROL_FAILED_VISIBLE_NULL(366, "KO", "Value1 is 'null'. This is mandatory in order to perform the control verify element visible", true, false, true, MessageGeneralEnum.EXECUTION_KO), CONTROL_FAILED_NOTVISIBLE_NULL(366, "KO", "Value1 is 'null'. This is mandatory in order to perform the control verify element not visible", true, false, true, MessageGeneralEnum.EXECUTION_KO), + CONTROL_FAILED_CHECKED_NULL(366, "KO", "Value1 is 'null'. This is mandatory in order to perform the control verify element checked", true, false, true, MessageGeneralEnum.EXECUTION_KO), + CONTROL_FAILED_NOTCHECKED_NULL(366, "KO", "Value1 is 'null'. This is mandatory in order to perform the control verify element not checked", true, false, true, MessageGeneralEnum.EXECUTION_KO), CONTROL_FAILED_ELEMENT_NULL(368, "KO", "Found Element '%ELEMENT%' but can not find text or value.", true, true, true, MessageGeneralEnum.EXECUTION_KO), CONTROL_FAILED_ELEMENT_NOSUCHELEMENT(369, "KO", "Could not find element '%ELEMENT%'", true, true, true, MessageGeneralEnum.EXECUTION_KO), CONTROL_FAILED_ELEMENTTEXTEQUAL(367, "KO", "Element '%ELEMENT%' with value '%ELEMENTVALUE%' is not equal to %VALUE% (%CASESENSITIVE%).", true, true, true, MessageGeneralEnum.EXECUTION_KO), diff --git a/source/src/main/java/org/cerberus/core/service/appium/IAppiumService.java b/source/src/main/java/org/cerberus/core/service/appium/IAppiumService.java index fb61035606..a05a965847 100644 --- a/source/src/main/java/org/cerberus/core/service/appium/IAppiumService.java +++ b/source/src/main/java/org/cerberus/core/service/appium/IAppiumService.java @@ -25,13 +25,11 @@ import org.cerberus.core.service.appium.SwipeAction.Direction; /** - * * @author bcivel */ public interface IAppiumService { /** - * * @param session * @param identifier * @return @@ -39,7 +37,13 @@ public interface IAppiumService { MessageEvent switchToContext(Session session, Identifier identifier); /** - * + * @param session Appium session + * @param context Name of the context to switch to + * @return Message to inform of the action result + */ + MessageEvent switchToContext(Session session, String context); + + /** * @param session * @param identifier * @return @@ -47,7 +51,6 @@ public interface IAppiumService { MessageEvent wait(Session session, Identifier identifier); /** - * * @param session * @param identifier * @param valueToType @@ -57,7 +60,6 @@ public interface IAppiumService { MessageEvent type(Session session, Identifier identifier, String valueToType, String propertyName); /** - * * @param session * @param identifier * @return @@ -65,7 +67,6 @@ public interface IAppiumService { MessageEvent click(Session session, Identifier identifier); /** - * * @param session * @param keyName * @return @@ -73,14 +74,12 @@ public interface IAppiumService { MessageEvent keyPress(Session session, String keyName); /** - * * @param session * @return */ MessageEvent hideKeyboard(Session session); /** - * * @param session * @param swipeAction * @return @@ -88,7 +87,6 @@ public interface IAppiumService { MessageEvent swipe(Session session, SwipeAction swipeAction); /** - * * @param session * @param action * @return @@ -97,7 +95,6 @@ public interface IAppiumService { Direction getDirectionForSwipe(Session session, SwipeAction action) throws IllegalArgumentException; /** - * * @param session * @param cmd * @param args @@ -111,7 +108,7 @@ public interface IAppiumService { * * @param session * @param element if not null or not empty, switch to this element - * @param text if not null or not empty, switch to this text + * @param text if not null or not empty, switch to this text * @return * @throws IllegalArgumentException */ @@ -156,7 +153,6 @@ public interface IAppiumService { MessageEvent closeApp(Session session); /** - * * @param session * @param identifier * @param pressDuration @@ -165,7 +161,6 @@ public interface IAppiumService { MessageEvent longPress(Session session, Identifier identifier, Integer pressDuration); /** - * * @param session * @param identifier * @return diff --git a/source/src/main/java/org/cerberus/core/service/appium/impl/AppiumService.java b/source/src/main/java/org/cerberus/core/service/appium/impl/AppiumService.java index c8cea81a50..97586a85a1 100644 --- a/source/src/main/java/org/cerberus/core/service/appium/impl/AppiumService.java +++ b/source/src/main/java/org/cerberus/core/service/appium/impl/AppiumService.java @@ -19,10 +19,8 @@ */ package org.cerberus.core.service.appium.impl; -import io.appium.java_client.AppiumDriver; -import io.appium.java_client.MobileBy; -import io.appium.java_client.MobileElement; -import io.appium.java_client.TouchAction; +import io.appium.java_client.NoSuchContextException; +import io.appium.java_client.*; import io.appium.java_client.touch.WaitOptions; import io.appium.java_client.touch.offset.ElementOption; import io.appium.java_client.touch.offset.PointOption; @@ -39,13 +37,7 @@ import org.cerberus.core.util.ParameterParserUtil; import org.cerberus.core.util.StringUtil; import org.json.JSONException; -import org.openqa.selenium.By; -import org.openqa.selenium.Dimension; -import org.openqa.selenium.NoSuchElementException; -import org.openqa.selenium.Point; -import org.openqa.selenium.TimeoutException; -import org.openqa.selenium.WebDriverException; -import org.openqa.selenium.WebElement; +import org.openqa.selenium.*; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; import org.springframework.beans.factory.annotation.Autowired; @@ -102,6 +94,30 @@ public MessageEvent switchToContext(Session session, Identifier identifier) { return message; } + @Override + public MessageEvent switchToContext(Session session, String context) { + MessageEvent message; + AppiumDriver driver = session.getAppiumDriver(); + Set contexts = driver.getContextHandles(); + + try { + if (context.isEmpty()) { + context = "NATIVE_APP"; + } + driver.context(context); + message = new MessageEvent(MessageEventEnum.ACTION_SUCCESS_SWITCHTOCONTEXT); + message.setDescription(message.getDescription().replace("%CONTEXT%", context)); + } catch (NoSuchContextException exception) { + LOG.error("Impossible to change the context: ", exception); + message = new MessageEvent(MessageEventEnum.ACTION_FAILED_SWITCHTOCONTEXT_NO_SUCH_ELEMENT); + message.setDescription(message.getDescription() + .replace("%CONTEXT%", context) + .replace("%CONTEXTS%", contexts.toString()) + .replace("%ERROR%", exception.getMessage())); + } + return message; + } + @Override public MessageEvent wait(Session session, Identifier identifier) { MessageEvent message; @@ -410,8 +426,8 @@ private boolean scrollDown(AppiumDriver driver, By element, int numberOfScrollDo } private void scroll(AppiumDriver driver, int fromX, int fromY, int toX, int toY) { - TouchAction touchAction = new TouchAction(driver); + TouchAction touchAction = new TouchAction(driver); touchAction.longPress(PointOption.point(fromX, fromY)).moveTo(PointOption.point(toX, toY)).release().perform(); } diff --git a/source/src/main/java/org/cerberus/core/service/appservice/IServiceService.java b/source/src/main/java/org/cerberus/core/service/appservice/IServiceService.java index 4610753b9b..4031431a03 100644 --- a/source/src/main/java/org/cerberus/core/service/appservice/IServiceService.java +++ b/source/src/main/java/org/cerberus/core/service/appservice/IServiceService.java @@ -44,8 +44,9 @@ public interface IServiceService { * @param servicePath * @param operation * @param tCExecution + * @param timeoutMs * @return */ - AnswerItem callService(String service, String targetNbEvents, String targetNbSec, String database, String request, String servicePath, String operation, TestCaseExecution tCExecution); + AnswerItem callService(String service, String targetNbEvents, String targetNbSec, String database, String request, String servicePath, String operation, TestCaseExecution tCExecution, int timeoutMs); } diff --git a/source/src/main/java/org/cerberus/core/service/appservice/impl/ServiceService.java b/source/src/main/java/org/cerberus/core/service/appservice/impl/ServiceService.java index 22b35765e8..3e71bb5f6f 100644 --- a/source/src/main/java/org/cerberus/core/service/appservice/impl/ServiceService.java +++ b/source/src/main/java/org/cerberus/core/service/appservice/impl/ServiceService.java @@ -47,6 +47,7 @@ import java.util.ArrayList; import java.util.List; import org.cerberus.core.service.csvfile.ICsvFileService; +import org.cerberus.core.service.mongodb.IMongodbService; /** * @author bcivel @@ -72,6 +73,8 @@ public class ServiceService implements IServiceService { @Autowired private IRestService restService; @Autowired + private IMongodbService mongodbService; + @Autowired private IKafkaService kafkaService; @Autowired private IFtpService ftpService; @@ -79,7 +82,7 @@ public class ServiceService implements IServiceService { private ICountryEnvironmentDatabaseService countryEnvironmentDatabaseService; @Override - public AnswerItem callService(String service, String targetNbEvents, String targetNbSec, String database, String request, String servicePathParam, String operation, TestCaseExecution tCExecution) { + public AnswerItem callService(String service, String targetNbEvents, String targetNbSec, String database, String request, String servicePathParam, String operation, TestCaseExecution tCExecution, int timeoutMs) { MessageEvent message = new MessageEvent(MessageEventEnum.ACTION_FAILED_CALLSERVICE); String decodedRequest; String decodedServicePath = null; @@ -99,14 +102,13 @@ public AnswerItem callService(String service, String targetNbEvents, if (StringUtil.isEmpty(service)) { LOG.debug("Creating AppService from parameters."); appService = factoryAppService.create("null", AppService.TYPE_SOAP, "", "", "", request, "", "", "", "", "", "", "Automatically created Service from datalib.", - servicePathParam, true, "", operation, false, "", "", null, null, null, null, null, null); + servicePathParam, true, "", operation, false, "", false, "", false, "", null, null, null, null, null, null); service = "null"; } else { // If Service information is defined, we get it from database. LOG.debug("Getting AppService from service : " + service); appService = appServiceService.convert(appServiceService.readByKeyWithDependency(service, true)); - } String servicePath; @@ -147,8 +149,8 @@ public AnswerItem callService(String service, String targetNbEvents, return result; } - // Autocomplete of service path is disable for KAFKA service (this is because there could be a list of host). - if (!appService.getType().equals(AppService.TYPE_KAFKA)) { + // Autocomplete of service path is disable for KAFKA and MONGODB service (this is because there could be a list of host). + if (!appService.getType().equals(AppService.TYPE_KAFKA) && !appService.getType().equals(AppService.TYPE_MONGODB)) { if (!(StringUtil.isURL(servicePath))) { // The URL defined inside the Service or directly from parameter is not complete and we need to add the first part taken either @@ -332,7 +334,9 @@ public AnswerItem callService(String service, String targetNbEvents, token = String.valueOf(tCExecution.getId()); } // Get from parameter the call timeout to be used. - int timeOutMs = parameterService.getParameterIntegerByKey("cerberus_callservice_timeoutms", system, 60000); + if (timeoutMs == 0) { + timeoutMs = parameterService.getParameterIntegerByKey("cerberus_callservice_timeoutms", system, 60000); + } // The rest of the data will be prepared depending on the TYPE and METHOD used. switch (appService.getType()) { case AppService.TYPE_SOAP: @@ -383,7 +387,7 @@ public AnswerItem callService(String service, String targetNbEvents, * Call SOAP and store it into the execution. */ result = soapService.callSOAP(decodedRequest, decodedServicePath, decodedOperation, decodedAttachement, - appService.getHeaderList(), token, timeOutMs, system); + appService.getHeaderList(), token, timeoutMs, system); LOG.debug("SOAP Called done."); LOG.debug("Result message." + result.getResultMessage()); @@ -407,7 +411,7 @@ public AnswerItem callService(String service, String targetNbEvents, * Call REST and store it into the execution. */ result = restService.callREST(decodedServicePath, decodedRequest, appService.getMethod(), - appService.getHeaderList(), appService.getContentList(), token, timeOutMs, system, appService.isFollowRedir(), tCExecution); + appService.getHeaderList(), appService.getContentList(), token, timeoutMs, system, appService.isFollowRedir(), tCExecution); message = result.getResultMessage(); break; @@ -419,6 +423,33 @@ public AnswerItem callService(String service, String targetNbEvents, break; + /** + * KAFKA. + */ + case AppService.TYPE_MONGODB: + + /** + * MONGODB. + */ + switch (appService.getMethod()) { + + case AppService.METHOD_MONGODBFIND: + /** + * Call MONGODB and store it into the execution. + */ + result = mongodbService.callMONGODB(decodedServicePath, decodedRequest, appService.getMethod(), + appService.getOperation(), timeoutMs, system, tCExecution); + message = result.getResultMessage(); + break; + + default: + message = new MessageEvent(MessageEventEnum.ACTION_FAILED_CALLSERVICE); + message.setDescription(message.getDescription().replace("%DESCRIPTION%", "Method : '" + appService.getMethod() + "' for MONGODB Service is not supported by the engine.")); + result.setResultMessage(message); + } + + break; + /** * KAFKA. */ @@ -450,6 +481,21 @@ public AnswerItem callService(String service, String targetNbEvents, return result; } + String decodedSchemaRegistryURL = appService.getSchemaRegistryURL(); + if (appService.isAvroEnable()) { + answerDecode = variableService.decodeStringCompletly(decodedSchemaRegistryURL, tCExecution, null, false); + decodedSchemaRegistryURL = answerDecode.getItem(); + if (!(answerDecode.isCodeStringEquals("OK"))) { + // If anything wrong with the decode --> we stop here with decode message in the action result. + String field = "Kafka Schema Registry URL"; + message = new MessageEvent(MessageEventEnum.ACTION_FAILED_CALLSERVICE) + .resolveDescription("DESCRIPTION", answerDecode.getResultMessage().resolveDescription("FIELD", field).getDescription()); + LOG.debug("Service Call interupted due to decode '" + field + "'."); + result.setResultMessage(message); + return result; + } + } + switch (appService.getMethod()) { case AppService.METHOD_KAFKAPRODUCE: @@ -457,7 +503,7 @@ public AnswerItem callService(String service, String targetNbEvents, * Call REST and store it into the execution. */ result = kafkaService.produceEvent(decodedTopic, decodedKey, decodedRequest, decodedServicePath, appService.getHeaderList(), appService.getContentList(), - token, appService.isAvroEnable(), appService.getSchemaRegistryURL(), appService.getAvroSchema(), timeOutMs); + token, appService.isAvroEnable(), decodedSchemaRegistryURL, appService.isAvroEnableKey(), appService.getAvroSchemaKey(), appService.isAvroEnableValue(), appService.getAvroSchemaValue(), timeoutMs); message = result.getResultMessage(); break; @@ -467,6 +513,7 @@ public AnswerItem callService(String service, String targetNbEvents, String decodedFilterValue = appService.getKafkaFilterValue(); String decodedFilterHeaderPath = appService.getKafkaFilterHeaderPath(); String decodedFilterHeaderValue = appService.getKafkaFilterHeaderValue(); + try { answerDecode = variableService.decodeStringCompletly(decodedFilterPath, tCExecution, null, false); @@ -547,11 +594,13 @@ public AnswerItem callService(String service, String targetNbEvents, appService.setKafkaResponseOffset(-1); appService.setKafkaFilterPath(decodedFilterPath); appService.setKafkaFilterValue(decodedFilterValue); + appService.setKafkaFilterHeaderPath(decodedFilterHeaderPath); + appService.setKafkaFilterHeaderValue(decodedFilterHeaderValue); String kafkaKey = kafkaService.getKafkaConsumerKey(decodedTopic, decodedServicePath); - AnswerItem resultSearch = kafkaService.searchEvent(tCExecution.getKafkaLatestOffset().get(kafkaKey), decodedTopic, decodedServicePath, - appService.getHeaderList(), appService.getContentList(), decodedFilterPath, decodedFilterValue, decodedFilterHeaderPath, decodedFilterHeaderValue, - appService.isAvroEnable(), appService.getSchemaRegistryURL(), targetNbEventsInt, targetNbSecInt); + AnswerItem resultSearch = kafkaService.searchEvent(tCExecution.getKafkaLatestOffset().get(kafkaKey), decodedTopic, decodedServicePath, + appService.getHeaderList(), appService.getContentList(), decodedFilterPath, decodedFilterValue, decodedFilterHeaderPath, decodedFilterHeaderValue, + appService.isAvroEnable(), decodedSchemaRegistryURL, appService.isAvroEnableKey(), appService.isAvroEnableValue(), targetNbEventsInt, targetNbSecInt); if (!(resultSearch.isCodeStringEquals("OK"))) { message = new MessageEvent(MessageEventEnum.ACTION_FAILED_CALLSERVICE); diff --git a/source/src/main/java/org/cerberus/core/service/ciresult/impl/CIService.java b/source/src/main/java/org/cerberus/core/service/ciresult/impl/CIService.java index 351a5e6b16..e9a85e06a5 100644 --- a/source/src/main/java/org/cerberus/core/service/ciresult/impl/CIService.java +++ b/source/src/main/java/org/cerberus/core/service/ciresult/impl/CIService.java @@ -384,7 +384,7 @@ public CICampaignResult getCIResultApi(String tag, String campaign) { @Override public String getFinalResult(int resultCal, int resultCalThreshold, int nbtotal, int nbok) { - if ((resultCal < resultCalThreshold) && (nbtotal > 0) && nbok > 0) { + if ((resultCal < resultCalThreshold) && (nbtotal > 0)) { return "OK"; } else { return "KO"; diff --git a/source/src/main/java/org/cerberus/core/service/datalib/impl/DataLibService.java b/source/src/main/java/org/cerberus/core/service/datalib/impl/DataLibService.java index f110f5456c..1f4d6d5b61 100644 --- a/source/src/main/java/org/cerberus/core/service/datalib/impl/DataLibService.java +++ b/source/src/main/java/org/cerberus/core/service/datalib/impl/DataLibService.java @@ -833,7 +833,7 @@ private AnswerList> getDataObjectList(TestDataLib lib, H columnsToHide = getListOfSecrets(lib.getTestDataLibID()); // Service Call is made here. - AnswerItem ai = serviceService.callService(lib.getService(), null, null, lib.getDatabaseUrl(), lib.getEnvelope(), lib.getServicePath(), lib.getMethod(), execution); + AnswerItem ai = serviceService.callService(lib.getService(), null, null, lib.getDatabaseUrl(), lib.getEnvelope(), lib.getServicePath(), lib.getMethod(), execution, 0); msg = ai.getResultMessage(); diff --git a/source/src/main/java/org/cerberus/core/service/ftp/impl/FtpService.java b/source/src/main/java/org/cerberus/core/service/ftp/impl/FtpService.java index 79d9263586..d5e75cbc7d 100644 --- a/source/src/main/java/org/cerberus/core/service/ftp/impl/FtpService.java +++ b/source/src/main/java/org/cerberus/core/service/ftp/impl/FtpService.java @@ -165,7 +165,7 @@ public AnswerItem callFTP(String chain, String system, String conten FTPClient ftp = new FTPClient(); AppService myResponse = factoryAppService.create(service, AppService.TYPE_FTP, - method, "", "", content, "", "", "", "", "", "", "", informations.get("path"), true, "", "", false, "", "", "", "", null, "", null, filePath); + method, "", "", content, "", "", "", "", "", "", "", informations.get("path"), true, "", "", false, "", false, "", false, "", "", "", null, "", null, filePath); try { if (proxyService.useProxy(StringUtil.getURLFromString(informations.get("host"), "", "", "ftp://"), system)) { diff --git a/source/src/main/java/org/cerberus/core/service/kafka/IKafkaService.java b/source/src/main/java/org/cerberus/core/service/kafka/IKafkaService.java index e2679f5e6b..0dd249ddbc 100644 --- a/source/src/main/java/org/cerberus/core/service/kafka/IKafkaService.java +++ b/source/src/main/java/org/cerberus/core/service/kafka/IKafkaService.java @@ -57,20 +57,25 @@ public interface IKafkaService { * @param token * @param isAvroEnable * @param schemaRegistryURL - * @param avroSchema + * @param isAvroEnableKey + * @param avroSchemaKey + * @param isAvroEnableValue + * @param avroSchemaValue * @param timeoutMs * @return */ public AnswerItem produceEvent(String topic, String key, String eventMessage, - String bootstrapServers, List serviceHeader, List serviceContent, String token, boolean isAvroEnable, String schemaRegistryURL, String avroSchema, int timeoutMs); + String bootstrapServers, List serviceHeader, List serviceContent, String token, + boolean isAvroEnable, String schemaRegistryURL, boolean isAvroEnableKey, String avroSchemaKey, boolean isAvroEnableValue, String avroSchemaValue, int timeoutMs); /** + * Get the last offset of every partition. * * @param topic * @param bootstrapServers * @param serviceHeader * @param timeoutMs - * @return + * @return a map that contain the last offset of every partition. * @throws InterruptedException * @throws ExecutionException */ @@ -90,16 +95,20 @@ public AnswerItem> seekEvent(String topic, String boot * @param targetNbEventsInt * @param filterHeaderValue * @param avroEnable + * @param avroEnableKey + * @param avroEnableValue * @param schemaRegistryURL * @param targetNbSecInt * @return */ public AnswerItem searchEvent(Map mapOffsetPosition, String topic, String bootstrapServers, - List serviceHeader, List serviceContent, String filterPath, String filterValue, String filterHeaderPath, String filterHeaderValue, - boolean avroEnable, String schemaRegistryURL, int targetNbEventsInt, int targetNbSecInt); + List serviceHeader, List serviceContent, String filterPath, String filterValue, String filterHeaderPath, String filterHeaderValue, + boolean avroEnable, String schemaRegistryURL, boolean avroEnableKey, boolean avroEnableValue, int targetNbEventsInt, int targetNbSecInt); /** - * Get the latest Offset of all partitions. + * Get the latest Offset of all partitions. This is triggered at the + * beginning of the execution only when at least a SEARCH KAFKA service is + * called. * * @param mainExecutionTestCaseStepList * @param tCExecution diff --git a/source/src/main/java/org/cerberus/core/service/kafka/impl/KafkaService.java b/source/src/main/java/org/cerberus/core/service/kafka/impl/KafkaService.java index e7a0b9bc9f..91a5875ed5 100644 --- a/source/src/main/java/org/cerberus/core/service/kafka/impl/KafkaService.java +++ b/source/src/main/java/org/cerberus/core/service/kafka/impl/KafkaService.java @@ -195,11 +195,12 @@ private Object readFrom(String jsonString, ParsedSchema parsedSchema) { @Override public AnswerItem produceEvent(String topic, String key, String eventMessage, String bootstrapServers, - List serviceHeader, List serviceContent, String token, boolean activateAvro, String schemaRegistryURL, String avroSchema, int timeoutMs) { + List serviceHeader, List serviceContent, String token, boolean activateAvro, String schemaRegistryURL, + boolean isAvroEnableKey, String avroSchemaKey, boolean isAvroEnableValue, String avroSchemaValue, int timeoutMs) { MessageEvent message = new MessageEvent(MessageEventEnum.ACTION_FAILED_CALLSERVICE_PRODUCEKAFKA); AnswerItem result = new AnswerItem<>(); - AppService serviceREST = factoryAppService.create("", AppService.TYPE_KAFKA, AppService.METHOD_KAFKAPRODUCE, "", "", "", "", "", "", "", "", "", "", "", true, "", "", false, "", "", null, + AppService serviceREST = factoryAppService.create("", AppService.TYPE_KAFKA, AppService.METHOD_KAFKAPRODUCE, "", "", "", "", "", "", "", "", "", "", "", true, "", "", false, "", false, "", false, "", null, "", null, "", null, null); // If token is defined, we add 'cerberus-token' on the http header. @@ -214,14 +215,23 @@ public AnswerItem produceEvent(String topic, String key, String even serviceContent.add(factoryAppServiceContent.create(null, ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer", true, 0, "", "", null, "", null)); serviceContent.add(factoryAppServiceContent.create(null, ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer", true, 0, "", "", null, "", null)); } else { - serviceContent.add(factoryAppServiceContent.create(null, ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer", true, 0, "", "", null, "", null)); - serviceContent.add(factoryAppServiceContent.create(null, ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, "io.confluent.kafka.serializers.KafkaAvroSerializer", true, 0, "", "", null, "", null)); + if (isAvroEnableKey) { + serviceContent.add(factoryAppServiceContent.create(null, ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, "io.confluent.kafka.serializers.KafkaAvroSerializer", true, 0, "", "", null, "", null)); + } else { + serviceContent.add(factoryAppServiceContent.create(null, ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer", true, 0, "", "", null, "", null)); + } + if (isAvroEnableValue) { + serviceContent.add(factoryAppServiceContent.create(null, ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, "io.confluent.kafka.serializers.KafkaAvroSerializer", true, 0, "", "", null, "", null)); + } else { + serviceContent.add(factoryAppServiceContent.create(null, ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer", true, 0, "", "", null, "", null)); + } // props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, KafkaAvroSerializer.class); serviceContent.add(factoryAppServiceContent.create(null, "schema.registry.url", schemaRegistryURL, true, 0, "", "", null, "", null)); } // Setting timeout although does not seem to work fine as result on aiven is always 60000 ms. serviceContent.add(factoryAppServiceContent.create(null, ProducerConfig.REQUEST_TIMEOUT_MS_CONFIG, String.valueOf(timeoutMs), true, 0, "", "", null, "", null)); serviceContent.add(factoryAppServiceContent.create(null, ProducerConfig.DELIVERY_TIMEOUT_MS_CONFIG, String.valueOf(timeoutMs), true, 0, "", "", null, "", null)); + serviceContent.add(factoryAppServiceContent.create(null, ProducerConfig.MAX_BLOCK_MS_CONFIG, String.valueOf(timeoutMs), true, 0, "", "", null, "", null)); for (AppServiceContent object : serviceContent) { if (object.isActive()) { @@ -246,53 +256,31 @@ public AnswerItem produceEvent(String topic, String key, String even if (activateAvro) { -// String userSchema = "{" -// + " \"name\": \"ProductGenericEvent\"," -// + " \"type\": \"record\"," -// + " \"namespace\": \"fr.adeo.redwood.event.avro.product\"," -// + " \"fields\": [" -// + " {" -// + " \"name\": \"id\"," -// + " \"type\": \"string\"" -// + " }," -// + " {" -// + " \"name\": \"timestamp\"," -// + " \"type\": \"long\"" -// + " }," -// + " {" -// + " \"name\": \"eventType\"," -// + " \"type\": \"string\"" -// + " }," -// + " {" -// + " \"name\": \"productReferenceAdeo\"," -// + " \"type\": \"int\"" -// + " }," -// + " {" -// + " \"name\": \"productReferenceBU\"," -// + " \"type\": \"int\"" -//// + " \"type\": [\"int\",\"null\"]," -//// + " \"default\":null" -// + " }," -// + " {" -// + " \"name\": \"codeBU\"," -// + " \"type\": \"string\"" -// + " }," -// + " {" -// + " \"name\": \"source\"," -// + " \"type\": \"string\"" -// + " }" -// + " ]" -// + "}"; -// -// LOG.debug("userSchema"); -// LOG.debug(userSchema); Schema.Parser parser = new Schema.Parser(); - Schema schema = parser.parse(avroSchema); + Schema schemaValue; + Schema schemaKey; + // ParsedSchema toto ; + ProducerRecord record; + if (isAvroEnableKey) { + if (isAvroEnableValue) { + schemaKey = parser.parse(avroSchemaKey); + schemaValue = parser.parse(avroSchemaValue); + record = new ProducerRecord<>(topic, jsonToAvro(key, schemaKey), jsonToAvro(eventMessage, schemaValue)); + } else { + schemaKey = parser.parse(avroSchemaKey); + record = new ProducerRecord<>(topic, jsonToAvro(key, schemaKey), eventMessage); + } + } else { + if (isAvroEnableValue) { + schemaValue = parser.parse(avroSchemaValue); + record = new ProducerRecord<>(topic, key, jsonToAvro(eventMessage, schemaValue)); + } else { + record = new ProducerRecord<>(topic, key, eventMessage); + } + } // GenericRecord eventMessageGeneric = new GenericData.Record(schema); - ProducerRecord record = new ProducerRecord<>(topic, key, jsonToAvro(eventMessage, schema)); - for (AppServiceHeader object : serviceHeader) { if (object.isActive()) { record.headers().add(new RecordHeader(object.getKey(), object.getValue().getBytes())); @@ -429,7 +417,7 @@ public AnswerItem> seekEvent(String topic, String boot @Override public AnswerItem searchEvent(Map mapOffsetPosition, String topic, String bootstrapServers, List serviceHeader, List serviceContent, String filterPath, String filterValue, String filterHeaderPath, String filterHeaderValue, - boolean activateAvro, String schemaRegistryURL, int targetNbEventsInt, int targetNbSecInt) { + boolean activateAvro, String schemaRegistryURL, boolean avroEnableKey, boolean avroEnableValue, int targetNbEventsInt, int targetNbSecInt) { MessageEvent message = new MessageEvent(MessageEventEnum.ACTION_FAILED_CALLSERVICE_SEARCHKAFKA); AnswerItem result = new AnswerItem<>(); @@ -447,12 +435,22 @@ public AnswerItem searchEvent(Map mapOffsetPositio serviceContent.add(factoryAppServiceContent.create(null, ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers, true, 0, "", "", null, "", null)); serviceContent.add(factoryAppServiceContent.create(null, ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "false", true, 0, "", "", null, "", null)); serviceContent.add(factoryAppServiceContent.create(null, ConsumerConfig.MAX_POLL_RECORDS_CONFIG, "10", true, 0, "", "", null, "", null)); + if (!activateAvro) { serviceContent.add(factoryAppServiceContent.create(null, ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer", true, 0, "", "", null, "", null)); serviceContent.add(factoryAppServiceContent.create(null, ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer", true, 0, "", "", null, "", null)); } else { - serviceContent.add(factoryAppServiceContent.create(null, ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer", true, 0, "", "", null, "", null)); - serviceContent.add(factoryAppServiceContent.create(null, ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, "io.confluent.kafka.serializers.KafkaAvroDeserializer", true, 0, "", "", null, "", null)); + if (avroEnableKey) { + serviceContent.add(factoryAppServiceContent.create(null, ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, "io.confluent.kafka.serializers.KafkaAvroDeserializer", true, 0, "", "", null, "", null)); + } else { + serviceContent.add(factoryAppServiceContent.create(null, ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer", true, 0, "", "", null, "", null)); + } + if (avroEnableValue) { + serviceContent.add(factoryAppServiceContent.create(null, ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, "io.confluent.kafka.serializers.KafkaAvroDeserializer", true, 0, "", "", null, "", null)); + } else { + serviceContent.add(factoryAppServiceContent.create(null, ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer", true, 0, "", "", null, "", null)); + } +// props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, KafkaAvroSerializer.class); serviceContent.add(factoryAppServiceContent.create(null, "schema.registry.url", schemaRegistryURL, true, 0, "", "", null, "", null)); } @@ -565,66 +563,220 @@ public AnswerItem searchEvent(Map mapOffsetPositio } else { - // AVRO VERSION - @SuppressWarnings("unchecked") - ConsumerRecords recordsAvro = consumer.poll(Duration.ofSeconds(pollDurationSec)); - LOG.debug("End Poll."); - if (Instant.now().toEpochMilli() > timeoutTime) { - LOG.debug("Timed out searching for record"); - consumer.wakeup(); //exit - } - //Now for each record in the batch of records we got from Kafka - for (ConsumerRecord record : recordsAvro) { - try { - LOG.debug("New record " + record.topic() + " " + record.partition() + " " + record.offset()); - LOG.debug(" " + record.key() + " | " + record.value()); + if (avroEnableKey) { - // Parsing header. - JSONObject headerJSON = new JSONObject(); - for (Header header : record.headers()) { - String headerKey = header.key(); - String headerValue = new String(header.value()); - headerJSON.put(headerKey, headerValue); + if (avroEnableValue) { + + // AVRO KEY+VALUE VERSION + @SuppressWarnings("unchecked") + ConsumerRecords recordsAvro = consumer.poll(Duration.ofSeconds(pollDurationSec)); + LOG.debug("End Poll."); + if (Instant.now().toEpochMilli() > timeoutTime) { + LOG.debug("Timed out searching for record"); + consumer.wakeup(); //exit + } + //Now for each record in the batch of records we got from Kafka + for (ConsumerRecord record : recordsAvro) { + try { + LOG.debug("New record " + record.topic() + " " + record.partition() + " " + record.offset()); + LOG.debug(" " + record.key() + " | " + record.value()); + + // Parsing header. + JSONObject headerJSON = new JSONObject(); + for (Header header : record.headers()) { + String headerKey = header.key(); + String headerValue = new String(header.value()); + headerJSON.put(headerKey, headerValue); + } + + boolean recordError = false; + + // Parsing message. + JSONObject recordJSON = new JSONObject(); + try { + recordJSON = new JSONObject(record.value().toString()); + } catch (JSONException ex) { + LOG.error(ex, ex); + recordError = true; + } + + // Parsing message. + JSONObject keyJSON = new JSONObject(); + try { + keyJSON = new JSONObject(record.key().toString()); + } catch (JSONException ex) { + LOG.error(ex, ex); + recordError = true; + } + + // Complete event with headers. + JSONObject messageJSON = new JSONObject(); + messageJSON.put("key", keyJSON); + messageJSON.put("value", recordJSON); + messageJSON.put("offset", record.offset()); + messageJSON.put("partition", record.partition()); + messageJSON.put("header", headerJSON); + + nbEvents++; + + boolean match = isRecordMatch(record.value().toString(), filterPath, filterValue, messageJSON.toString(), filterHeaderPath, filterHeaderValue); + + if (match) { + resultJSON.put(messageJSON); + nbFound++; + if (nbFound >= targetNbEventsInt) { + consume = false; //exit the consume loop + consumer.wakeup(); //takes effect on the next poll loop so need to break. + break; //if we've found a match, stop looping through the current record batch + } + } + + } catch (Exception ex) { + //Catch any exceptions thrown from message processing/testing as they should have already been reported/dealt with + //but we don't want to trigger the catch block for Kafka consumption + LOG.error(ex, ex); + } } - boolean recordError = false; + } else { - // Parsing message. - JSONObject recordJSON = new JSONObject(); - try { - recordJSON = new JSONObject(record.value().toString()); - } catch (JSONException ex) { - LOG.error(ex, ex); - recordError = true; + // AVRO KEY VERSION + @SuppressWarnings("unchecked") + ConsumerRecords recordsAvro = consumer.poll(Duration.ofSeconds(pollDurationSec)); + LOG.debug("End Poll."); + if (Instant.now().toEpochMilli() > timeoutTime) { + LOG.debug("Timed out searching for record"); + consumer.wakeup(); //exit + } + //Now for each record in the batch of records we got from Kafka + for (ConsumerRecord record : recordsAvro) { + try { + LOG.debug("New record " + record.topic() + " " + record.partition() + " " + record.offset()); + LOG.debug(" " + record.key() + " | " + record.value()); + + // Parsing header. + JSONObject headerJSON = new JSONObject(); + for (Header header : record.headers()) { + String headerKey = header.key(); + String headerValue = new String(header.value()); + headerJSON.put(headerKey, headerValue); + } + + boolean recordError = false; + + // Parsing message. + JSONObject recordJSON = new JSONObject(); + try { + recordJSON = new JSONObject(record.value()); + } catch (JSONException ex) { + LOG.error(ex, ex); + recordError = true; + } + + // Parsing message. + JSONObject keyJSON = new JSONObject(); + try { + keyJSON = new JSONObject(record.key().toString()); + } catch (JSONException ex) { + LOG.error(ex, ex); + recordError = true; + } + + // Complete event with headers. + JSONObject messageJSON = new JSONObject(); + messageJSON.put("key", keyJSON); + messageJSON.put("value", record.value()); + messageJSON.put("offset", record.offset()); + messageJSON.put("partition", record.partition()); + messageJSON.put("header", headerJSON); + + nbEvents++; + + boolean match = isRecordMatch(record.value(), filterPath, filterValue, messageJSON.toString(), filterHeaderPath, filterHeaderValue); + + if (match) { + resultJSON.put(messageJSON); + nbFound++; + if (nbFound >= targetNbEventsInt) { + consume = false; //exit the consume loop + consumer.wakeup(); //takes effect on the next poll loop so need to break. + break; //if we've found a match, stop looping through the current record batch + } + } + + } catch (Exception ex) { + //Catch any exceptions thrown from message processing/testing as they should have already been reported/dealt with + //but we don't want to trigger the catch block for Kafka consumption + LOG.error(ex, ex); + } } - // Complete event with headers. - JSONObject messageJSON = new JSONObject(); - messageJSON.put("key", record.key()); - messageJSON.put("value", recordJSON); - messageJSON.put("offset", record.offset()); - messageJSON.put("partition", record.partition()); - messageJSON.put("header", headerJSON); + } - nbEvents++; + } else { - boolean match = isRecordMatch(record.value().toString(), filterPath, filterValue, messageJSON.toString(), filterHeaderPath, filterHeaderValue); + // AVRO VALUE VERSION + @SuppressWarnings("unchecked") + ConsumerRecords recordsAvro = consumer.poll(Duration.ofSeconds(pollDurationSec)); + LOG.debug("End Poll."); + if (Instant.now().toEpochMilli() > timeoutTime) { + LOG.debug("Timed out searching for record"); + consumer.wakeup(); //exit + } + //Now for each record in the batch of records we got from Kafka + for (ConsumerRecord record : recordsAvro) { + try { + LOG.debug("New record " + record.topic() + " " + record.partition() + " " + record.offset()); + LOG.debug(" " + record.key() + " | " + record.value()); + + // Parsing header. + JSONObject headerJSON = new JSONObject(); + for (Header header : record.headers()) { + String headerKey = header.key(); + String headerValue = new String(header.value()); + headerJSON.put(headerKey, headerValue); + } - if (match) { - resultJSON.put(messageJSON); - nbFound++; - if (nbFound >= targetNbEventsInt) { - consume = false; //exit the consume loop - consumer.wakeup(); //takes effect on the next poll loop so need to break. - break; //if we've found a match, stop looping through the current record batch + boolean recordError = false; + + // Parsing message. + JSONObject recordJSON = new JSONObject(); + try { + recordJSON = new JSONObject(record.value().toString()); + } catch (JSONException ex) { + LOG.error(ex, ex); + recordError = true; } - } - } catch (Exception ex) { - //Catch any exceptions thrown from message processing/testing as they should have already been reported/dealt with - //but we don't want to trigger the catch block for Kafka consumption - LOG.error(ex, ex); + // Complete event with headers. + JSONObject messageJSON = new JSONObject(); + messageJSON.put("key", record.key()); + messageJSON.put("value", recordJSON); + messageJSON.put("offset", record.offset()); + messageJSON.put("partition", record.partition()); + messageJSON.put("header", headerJSON); + + nbEvents++; + + boolean match = isRecordMatch(record.value().toString(), filterPath, filterValue, messageJSON.toString(), filterHeaderPath, filterHeaderValue); + + if (match) { + resultJSON.put(messageJSON); + nbFound++; + if (nbFound >= targetNbEventsInt) { + consume = false; //exit the consume loop + consumer.wakeup(); //takes effect on the next poll loop so need to break. + break; //if we've found a match, stop looping through the current record batch + } + } + + } catch (Exception ex) { + //Catch any exceptions thrown from message processing/testing as they should have already been reported/dealt with + //but we don't want to trigger the catch block for Kafka consumption + LOG.error(ex, ex); + } } + } } diff --git a/source/src/main/java/org/cerberus/core/service/mongodb/IMongodbService.java b/source/src/main/java/org/cerberus/core/service/mongodb/IMongodbService.java new file mode 100644 index 0000000000..3d4441217c --- /dev/null +++ b/source/src/main/java/org/cerberus/core/service/mongodb/IMongodbService.java @@ -0,0 +1,46 @@ +/** + * Cerberus Copyright (C) 2013 - 2017 cerberustesting + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This file is part of Cerberus. + * + * Cerberus is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Cerberus is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Cerberus. If not, see . + */ +package org.cerberus.core.service.mongodb; + +import org.cerberus.core.crud.entity.AppService; +import org.cerberus.core.crud.entity.TestCaseExecution; +import org.cerberus.core.util.answer.AnswerItem; + +/** + * + * @author bcivel + */ +public interface IMongodbService { + + /** + * Call Soap Message + * + * @param servicePath + * @param queryString + * @param method + * @param operation Contains Database.Collection + * @param timeOutMs + * @param system + * @param tcexecution + * @return + */ + AnswerItem callMONGODB(String servicePath, String queryString, String method, String operation, int timeOutMs, String system, TestCaseExecution tcexecution); + +} diff --git a/source/src/main/java/org/cerberus/core/service/mongodb/impl/MongodbService.java b/source/src/main/java/org/cerberus/core/service/mongodb/impl/MongodbService.java new file mode 100644 index 0000000000..e9c28241dd --- /dev/null +++ b/source/src/main/java/org/cerberus/core/service/mongodb/impl/MongodbService.java @@ -0,0 +1,193 @@ +/** + * Cerberus Copyright (C) 2013 - 2017 cerberustesting + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This file is part of Cerberus. + * + * Cerberus is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Cerberus is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Cerberus. If not, see . + */ +package org.cerberus.core.service.mongodb.impl; + +import com.mongodb.BasicDBObject; +import com.mongodb.ConnectionString; +import com.mongodb.MongoClientSettings; +import com.mongodb.MongoSocketOpenException; +import com.mongodb.MongoTimeoutException; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoCursor; +import com.mongodb.client.MongoDatabase; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.cerberus.core.crud.entity.AppService; +import org.cerberus.core.crud.entity.TestCaseExecution; +import org.cerberus.core.crud.factory.IFactoryAppService; +import org.cerberus.core.crud.factory.IFactoryAppServiceHeader; +import org.cerberus.core.crud.service.IAppServiceService; +import org.cerberus.core.crud.service.IParameterService; +import org.cerberus.core.engine.entity.MessageEvent; +import org.cerberus.core.engine.execution.IRecorderService; +import org.cerberus.core.enums.MessageEventEnum; +import org.cerberus.core.service.proxy.IProxyService; +import org.cerberus.core.util.answer.AnswerItem; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Iterator; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import org.bson.Document; +import org.cerberus.core.service.mongodb.IMongodbService; +import org.json.JSONArray; +import org.json.JSONObject; + +/** + * @author bcivel + */ +@Service +public class MongodbService implements IMongodbService { + + @Autowired + IRecorderService recorderService; + @Autowired + IFactoryAppServiceHeader factoryAppServiceHeader; + @Autowired + IParameterService parameterService; + @Autowired + IFactoryAppService factoryAppService; + @Autowired + IAppServiceService AppServiceService; + @Autowired + IProxyService proxyService; + + private static final Logger LOG = LogManager.getLogger(MongodbService.class); + + @Override + public AnswerItem callMONGODB(String servicePath, String requestString, String method, String operation, int timeOutMs, + String system, TestCaseExecution tcexecution) { + MessageEvent message = null; + AnswerItem result = new AnswerItem<>(); + + AppService serviceMONGODB = factoryAppService.create("", AppService.TYPE_MONGODB, method, "", "", "", "", "", "", "", "", "", "", "", true, "", "", false, "", false, "", false, "", null, + "", null, "", null, null); + serviceMONGODB.setProxy(false); + serviceMONGODB.setProxyHost(null); + serviceMONGODB.setProxyPort(0); + serviceMONGODB.setServiceRequest(requestString); + serviceMONGODB.setOperation(operation); + serviceMONGODB.setServicePath(servicePath); + serviceMONGODB.setTimeoutms(timeOutMs); + String mongoDBResult = null; + JSONArray mongoDBResultArray = new JSONArray(); + + LOG.debug("Starting MONGODB Find. " + servicePath); + + try (MongoClient mongoClient = MongoClients.create(MongoClientSettings.builder().applyConnectionString(new ConnectionString(servicePath)) + .applyToSocketSettings(builder + -> builder.connectTimeout(timeOutMs, MILLISECONDS) // TODO Debug as still 30 sec. + .readTimeout(timeOutMs, MILLISECONDS)) // TODO Debug as still 30 sec. + .build())) { + + LOG.debug("Connection : " + operation); + String MDBdtb = operation.split("\\.")[0]; + String MDBColl = operation.split("\\.")[1]; + LOG.debug("Connection : " + MDBdtb + " / " + MDBColl); + MongoDatabase database = mongoClient.getDatabase(MDBdtb); + MongoCollection collection = database.getCollection(MDBColl); + +// Bson projectionFields = Projections.fields( +// Projections.include("title", "imdb"), +// Projections.excludeId()); +// Document doc = collection.find(eq("ID_CDE_GET", "7883")) +// .projection(projectionFields) +// .sort(Sorts.descending("imdb.rating")) +// .first(); +// Document doc = collection.find(eq("ID_CDE_GET", "7883")).first(); +// .projection(projectionFields) +// .sort(Sorts.descending("imdb.rating")) +// .first(); + + BasicDBObject whereQuery = new BasicDBObject(); + + JSONObject requestObject = new JSONObject(requestString); + + @SuppressWarnings("unchecked") + Iterator keys = requestObject.keys(); + + while (keys.hasNext()) { + String key = keys.next(); +// if (requestObject.get(key) instanceof String) { + whereQuery.put(key, requestObject.get(key)); +// } + } + LOG.debug("Parsed : " + requestObject); + LOG.debug("Parsed : " + whereQuery); + + MongoCursor cursor = collection.find(whereQuery) + // .projection(projectionFields) + .iterator(); + try { + int i = 0; + while (cursor.hasNext() && i < 5) { + LOG.debug("Results found."); + mongoDBResult = cursor.next().toJson(); + i++; + mongoDBResultArray.put(new JSONObject(mongoDBResult)); + LOG.debug(mongoDBResult); +// System.out.println(cursor.next().toJson()); + } + serviceMONGODB.setResponseHTTPBody(mongoDBResultArray.toString()); + serviceMONGODB.setResponseNb(i); + + } finally { + cursor.close(); + } + + } catch (MongoTimeoutException ex) { + LOG.info("Exception when performing the MONGODB Call. " + ex.toString()); + message = new MessageEvent(MessageEventEnum.ACTION_FAILED_CALLSERVICE_TIMEOUT); + message.resolveDescription("SERVICEURL", servicePath); + message.resolveDescription("TIMEOUT", String.valueOf(timeOutMs)); + message.resolveDescription("DESCRIPTION", ex.toString()); + result.setResultMessage(message); + return result; + } catch (MongoSocketOpenException ex) { + LOG.info("Exception when performing the MONGODB Call. " + ex.toString()); + message = new MessageEvent(MessageEventEnum.ACTION_FAILED_CALLSERVICE); + message.resolveDescription("DESCRIPTION", ex.toString()); + result.setResultMessage(message); + return result; + } catch (Exception ex) { + LOG.info("Exception when performing the MONGODB Call. " + ex.toString()); + message = new MessageEvent(MessageEventEnum.ACTION_FAILED_CALLSERVICE); + message.resolveDescription("DESCRIPTION", ex.toString()); + result.setResultMessage(message); + return result; + } + + // Get result Content Type. + if (mongoDBResult != null) { + serviceMONGODB.setResponseHTTPBodyContentType(AppServiceService.guessContentType(serviceMONGODB, AppService.RESPONSEHTTPBODYCONTENTTYPE_JSON)); + } + + result.setItem(serviceMONGODB); + message = new MessageEvent(MessageEventEnum.ACTION_SUCCESS_CALLSERVICE); + message.setDescription(message.getDescription().replace("%SERVICEMETHOD%", method)); + message.setDescription(message.getDescription().replace("%SERVICEPATH%", servicePath)); + result.setResultMessage(message); + return result; + + } + +} diff --git a/source/src/main/java/org/cerberus/core/service/notifications/email/impl/EmailGenerationService.java b/source/src/main/java/org/cerberus/core/service/notifications/email/impl/EmailGenerationService.java index 6409ec19b0..f555769a35 100644 --- a/source/src/main/java/org/cerberus/core/service/notifications/email/impl/EmailGenerationService.java +++ b/source/src/main/java/org/cerberus/core/service/notifications/email/impl/EmailGenerationService.java @@ -19,6 +19,7 @@ */ package org.cerberus.core.service.notifications.email.impl; +import java.net.URLEncoder; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.cerberus.core.crud.entity.BatchInvariant; @@ -73,7 +74,6 @@ public class EmailGenerationService implements IEmailGenerationService { @Autowired private IEmailBodyGeneration emailBodyGeneration; - @Override public Email generateRevisionChangeEmail(String system, String country, String env, String build, String revision) throws Exception { Email email = new Email(); @@ -318,7 +318,7 @@ public Email generateNotifyStartTagExecution(Tag tag, String to) throws Exceptio StringBuilder urlreporttag = new StringBuilder(); urlreporttag.append(cerberusUrl); urlreporttag.append("/ReportingExecutionByTag.jsp?Tag="); - urlreporttag.append(tag.getTag()); + urlreporttag.append(URLEncoder.encode(tag.getTag(), "UTF-8")); body = body.replace("%TAG%", tag.getTag()); body = body.replace("%URLTAGREPORT%", urlreporttag.toString()); body = body.replace("%CAMPAIGN%", tag.getCampaign()); @@ -362,7 +362,7 @@ public Email generateNotifyEndTagExecution(Tag tag, String to) throws Exception StringBuilder urlreporttag = new StringBuilder(); urlreporttag.append(cerberusUrl); urlreporttag.append("/ReportingExecutionByTag.jsp?Tag="); - urlreporttag.append(tag); + urlreporttag.append(URLEncoder.encode(URLEncoder.encode(tag.getTag(), "UTF-8"), "UTF-8")); // Body replace. body = body.replace("%TAG%", tag.getTag()); @@ -689,9 +689,9 @@ public Email generateNotifyTestCaseChange(TestCase testCase, String to, String e StringBuilder urlTestCase = new StringBuilder(); urlTestCase.append(cerberusUrl); urlTestCase.append("/TestCaseScript.jsp?test="); - urlTestCase.append(testCase.getTest()); + urlTestCase.append(URLEncoder.encode(testCase.getTest(), "UTF-8")); urlTestCase.append("&testcase="); - urlTestCase.append(testCase.getTestcase()); + urlTestCase.append(URLEncoder.encode(testCase.getTestcase(), "UTF-8")); switch (eventReference) { case EventHook.EVENTREFERENCE_TESTCASE_CREATE: diff --git a/source/src/main/java/org/cerberus/core/service/notifications/email/impl/EmailService.java b/source/src/main/java/org/cerberus/core/service/notifications/email/impl/EmailService.java index 3f1dfca672..ff884e2cd3 100644 --- a/source/src/main/java/org/cerberus/core/service/notifications/email/impl/EmailService.java +++ b/source/src/main/java/org/cerberus/core/service/notifications/email/impl/EmailService.java @@ -19,6 +19,7 @@ */ package org.cerberus.core.service.notifications.email.impl; +import java.nio.charset.Charset; import org.cerberus.core.service.notifications.email.entity.Email; import org.apache.commons.mail.HtmlEmail; import org.cerberus.core.crud.service.ILogEventService; @@ -51,6 +52,7 @@ public void sendHtmlMail(Email cerberusEmail) throws Exception { email.setFrom(cerberusEmail.getFrom()); email.setSubject(cerberusEmail.getSubject()); email.setHtmlMsg(cerberusEmail.getBody()); + email.setCharset("UTF-8"); if (cerberusEmail.isSetTls()) { email = (HtmlEmail) email.setStartTLSEnabled(true); } diff --git a/source/src/main/java/org/cerberus/core/service/pdf/IPDFService.java b/source/src/main/java/org/cerberus/core/service/pdf/IPDFService.java new file mode 100644 index 0000000000..c567e89348 --- /dev/null +++ b/source/src/main/java/org/cerberus/core/service/pdf/IPDFService.java @@ -0,0 +1,62 @@ +/** + * Cerberus Copyright (C) 2013 - 2017 cerberustesting + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This file is part of Cerberus. + * + * Cerberus is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Cerberus is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Cerberus. If not, see . + */ +package org.cerberus.core.service.pdf; + +import java.io.FileNotFoundException; +import java.util.Date; +import java.util.List; +import org.cerberus.core.crud.entity.Tag; + +/** + * @author bcivel + */ +public interface IPDFService { + + /** + * @param tag + * @param today + * @param folder + * @return + * @throws java.io.FileNotFoundException + */ + String generatePdf(Tag tag, Date today, String folder) throws FileNotFoundException; + + /** + * @param tag + * @param today + * @param folder + * @return + * @throws java.io.FileNotFoundException + */ + List generatePdfAppendix(Tag tag, Date today, String folder) throws FileNotFoundException; + + /** + * + * @param pdfFilePathSrc + * @param pdfFilePathDst + * @param tag + * @param today + * @param withLogo + * @return + * @throws FileNotFoundException + */ + String addHeaderAndFooter(String pdfFilePathSrc, String pdfFilePathDst, Tag tag, Date today, boolean withLogo) throws FileNotFoundException; + +} diff --git a/source/src/main/java/org/cerberus/core/service/pdf/impl/PDFService.java b/source/src/main/java/org/cerberus/core/service/pdf/impl/PDFService.java new file mode 100644 index 0000000000..a5640e891a --- /dev/null +++ b/source/src/main/java/org/cerberus/core/service/pdf/impl/PDFService.java @@ -0,0 +1,861 @@ +/** + * Cerberus Copyright (C) 2013 - 2017 cerberustesting + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This file is part of Cerberus. + * + * Cerberus is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Cerberus is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Cerberus. If not, see . + */ +package org.cerberus.core.service.pdf.impl; + +import com.itextpdf.html2pdf.HtmlConverter; +import com.itextpdf.io.image.ImageData; +import com.itextpdf.io.image.ImageDataFactory; +import com.itextpdf.kernel.colors.ColorConstants; +import com.itextpdf.kernel.colors.DeviceRgb; +import com.itextpdf.kernel.geom.Rectangle; +import com.itextpdf.kernel.pdf.PdfDocument; +import com.itextpdf.kernel.pdf.PdfPage; +import com.itextpdf.kernel.pdf.PdfReader; +import com.itextpdf.kernel.pdf.PdfWriter; +import com.itextpdf.kernel.pdf.action.PdfAction; +import com.itextpdf.layout.Document; +import com.itextpdf.layout.borders.Border; +import com.itextpdf.layout.borders.SolidBorder; +import com.itextpdf.layout.element.AreaBreak; +import com.itextpdf.layout.element.Cell; +import com.itextpdf.layout.element.IBlockElement; +import com.itextpdf.layout.element.IElement; +import com.itextpdf.layout.element.Image; +import com.itextpdf.layout.element.Paragraph; +import com.itextpdf.layout.element.Table; +import com.itextpdf.layout.element.Text; +import com.itextpdf.layout.properties.HorizontalAlignment; +import com.itextpdf.layout.properties.TextAlignment; +import com.itextpdf.layout.properties.VerticalAlignment; +import java.io.File; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.MalformedURLException; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import org.cerberus.core.crud.entity.Parameter; +import org.cerberus.core.crud.entity.Tag; +import org.cerberus.core.crud.entity.Test; +import org.cerberus.core.crud.entity.TestCaseExecution; +import org.cerberus.core.crud.entity.TestCaseExecutionFile; +import org.cerberus.core.crud.entity.TestCaseStepActionControlExecution; +import org.cerberus.core.crud.entity.TestCaseStepActionExecution; +import org.cerberus.core.crud.entity.TestCaseStepExecution; +import org.cerberus.core.crud.service.IParameterService; +import org.cerberus.core.crud.service.ITestCaseExecutionService; +import org.cerberus.core.exception.CerberusException; +import org.springframework.stereotype.Service; + +import org.cerberus.core.service.pdf.IPDFService; +import org.cerberus.core.util.DateUtil; +import org.cerberus.core.util.StringUtil; +import org.json.JSONArray; +import org.json.JSONException; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * @author bcivel + */ +@Service +public class PDFService implements IPDFService { + + private static final org.apache.logging.log4j.Logger LOG = org.apache.logging.log4j.LogManager.getLogger(PDFService.class); + + private final int NB_EXECUTION_PER_APPENDIX_FILE = 50; + + @Autowired + private ITestCaseExecutionService testCaseExecutionService; + @Autowired + private IParameterService parameterService; + + private Table getTitleTable(String desc1, String desc2) { + // Tittle + Table tableTitle = new Table(new float[]{600}); + Cell descCell = new Cell(); + descCell.add(new Paragraph(desc1).setBold().setFontSize(20).setTextAlignment(TextAlignment.CENTER)); + if (StringUtil.isNotEmptyOrNullValue(desc2)) { + descCell.add(new Paragraph(desc2).setBold().setItalic().setFontSize(20).setTextAlignment(TextAlignment.CENTER)); + } + descCell.setMarginBottom(30).setBorder(Border.NO_BORDER).setVerticalAlignment(VerticalAlignment.MIDDLE); + tableTitle.addCell(descCell); + return tableTitle; + } + + @Override + public String generatePdf(Tag tag, Date today, String folder) throws FileNotFoundException { + + UUID fileUUID = UUID.randomUUID(); + DateFormat df = new SimpleDateFormat(DateUtil.DATE_FORMAT_REPORT); + DateFormat dfEnd = new SimpleDateFormat(DateUtil.DATE_FORMAT_REPORT_TIME); + + // Creating a PdfWriter + String dest = folder + File.separatorChar + "Campaign Execution Report tmp.pdf"; + LOG.info("Starting to generate PDF Report on :" + dest); + PdfWriter writer = new PdfWriter(dest); + + // Creating a PdfDocument + PdfDocument pdfDoc = new PdfDocument(writer); + + boolean displayCountryColumn = parameterService.getParameterBooleanByKey(Parameter.VALUE_cerberus_pdfcampaignreportdisplaycountry_boolean, "", true); + + // Tittle + Table tableTitle = getTitleTable("Campaign Execution Report", tag.getTag()); + + try ( // Creating a Document + Document document = new Document(pdfDoc)) { + + AreaBreak aB = new AreaBreak(); + + // Tittle + document.add(tableTitle.setMarginLeft(0)); + + document.add(new Paragraph().add(getTextFromString("", 10, false))); + document.add(new Paragraph().add(getTextFromString("", 10, false))); + document.add(new Paragraph().add(getTextFromString("", 10, false))); + + if (!StringUtil.isEmptyOrNullValue(tag.getDescription())) { + List eleList = HtmlConverter.convertToElements(tag.getDescription()); + Table tableDesc = new Table(new float[]{1000}); + + Cell myCell = new Cell(); + for (IElement element : eleList) { + myCell.add((IBlockElement) element); + } + tableDesc.addCell(myCell.setBorder(Border.NO_BORDER)); + document.add(tableDesc); + } + + document.add(new Paragraph("Main technical details").setMarginTop(30).setMarginBottom(10).setBold().setFontSize(14)); + + long tagDur = (tag.getDateEndQueue().getTime() - tag.getDateCreated().getTime()) / 60000; + document.add(new Paragraph() + .add(getTextFromString("Report generated at ", 10, false)) + .add(getTextFromString(String.valueOf(df.format(today)), 12, true)) + ); + document.add(new Paragraph() + .add(getTextFromString("Campaign started at ", 10, false)) + .add(getTextFromString(String.valueOf(df.format(tag.getDateCreated().getTime())), 12, true)) + .add(getTextFromString(" and ended at ", 10, false)) + .add(getTextFromString(String.valueOf(df.format(tag.getDateEndQueue())), 12, true)) + .add(getTextFromString(" (duration of ", 10, false)) + .add(getTextFromString(String.valueOf(tagDur), 12, true)) + .add(getTextFromString(" min)", 10, false)) + ); + if (displayCountryColumn) { + document.add(new Paragraph() + .add(getTextFromString("Executed on Country(ies): ", 10, false)) + .add(getTextFromString(StringUtil.convertToString(new JSONArray(tag.getCountryList()), ","), 12, true)) + .add(getTextFromString(", Environment(s): ", 10, false)) + .add(getTextFromString(StringUtil.convertToString(new JSONArray(tag.getEnvironmentList()), ","), 12, true)) + .add(getTextFromString(" and Robot(s): ", 10, false)) + .add(getTextFromString(StringUtil.convertToString(new JSONArray(tag.getRobotDecliList()), ","), 12, true))); + } else { + document.add(new Paragraph() + .add(getTextFromString("Executed on Environment(s): ", 10, false)) + .add(getTextFromString(tag.getEnvironmentList() == null ? "" : StringUtil.convertToString(new JSONArray(tag.getEnvironmentList()), ","), 12, true)) + .add(getTextFromString(" and Robot(s): ", 10, false)) + .add(getTextFromString(tag.getRobotDecliList() == null ? "" : StringUtil.convertToString(new JSONArray(tag.getRobotDecliList()), ","), 12, true))); + } + + /** + * Result information per status + */ + document.add(new Paragraph("Global status").setMarginTop(30).setMarginBottom(10).setBold().setFontSize(14)); + // Creating a table + Table tableGlobalStatus = new Table(new float[]{50, 50, 40}) + .addHeaderCell(getHeaderCell("Status")) + .addHeaderCell(getHeaderCell("Number")) + .addHeaderCell(getHeaderCell("%")); + + // Map that will contain the color of every status. + Map statColorMap = new HashMap<>(); + statColorMap.put(TestCaseExecution.CONTROLSTATUS_OK, TestCaseExecution.CONTROLSTATUS_OK_COL_EXT); + statColorMap.put(TestCaseExecution.CONTROLSTATUS_KO, TestCaseExecution.CONTROLSTATUS_KO_COL_EXT); + statColorMap.put(TestCaseExecution.CONTROLSTATUS_FA, TestCaseExecution.CONTROLSTATUS_FA_COL_EXT); + statColorMap.put(TestCaseExecution.CONTROLSTATUS_NA, TestCaseExecution.CONTROLSTATUS_NA_COL_EXT); + statColorMap.put(TestCaseExecution.CONTROLSTATUS_NE, TestCaseExecution.CONTROLSTATUS_NE_COL_EXT); + statColorMap.put(TestCaseExecution.CONTROLSTATUS_WE, TestCaseExecution.CONTROLSTATUS_WE_COL_EXT); + statColorMap.put(TestCaseExecution.CONTROLSTATUS_PE, TestCaseExecution.CONTROLSTATUS_PE_COL_EXT); + statColorMap.put(TestCaseExecution.CONTROLSTATUS_QU, TestCaseExecution.CONTROLSTATUS_QU_COL_EXT); + statColorMap.put(TestCaseExecution.CONTROLSTATUS_QE, TestCaseExecution.CONTROLSTATUS_QE_COL_EXT); + statColorMap.put(TestCaseExecution.CONTROLSTATUS_CA, TestCaseExecution.CONTROLSTATUS_CA_COL_EXT); + + // Map that will contain the nb of execution for global status. + List listOfExecutions = testCaseExecutionService.readLastExecutionAndExecutionInQueueByTag(tag.getTag()); + Collections.sort(listOfExecutions, new SortExecution()); + + Map statNbMap = new HashMap<>(); + for (TestCaseExecution execution : listOfExecutions) { + if (statNbMap.get(execution.getControlStatus()) == null) { + statNbMap.put(execution.getControlStatus(), 0); + } + statNbMap.put(execution.getControlStatus(), statNbMap.get(execution.getControlStatus()) + 1); + } + + // Status list in the correct order. + float per = 0; + List statList = new ArrayList<>(Arrays.asList("OK", "KO", "FA", "NA", "NE", "WE", "PE", "QU", "QE", "CA")); + for (String string : statList) { + if ((statNbMap.get(string) != null) && (statNbMap.get(string) > 0)) { + per = statNbMap.get(string) / (float) tag.getNbExeUsefull(); + per *= 100; + tableGlobalStatus + .addCell(getStatusCell(string, 1, 1)) + .addCell(String.valueOf(statNbMap.get(string))).setTextAlignment(TextAlignment.RIGHT) + .addCell(String.format("%.2f", per)); + + } + } + document.add(tableGlobalStatus); + + document.add(aB); + + /** + * Summary result per execution + */ + document.add(getTitleTable("Execution list summary", "").setMarginLeft(0)); + + // Creating a table + Table tableExe; + if (displayCountryColumn) { + tableExe = new Table(new float[]{40, 140, 80, 20, 80, 20, 20, 50, 50, 50, 30}); + + } else { + tableExe = new Table(new float[]{40, 140, 80, 20, 80, 20, 50, 50, 50, 30}); + } + + tableExe.addHeaderCell(getHeaderCell("Exe ID")) + .addHeaderCell(getHeaderCell("Test Folder")) + .addHeaderCell(getHeaderCell("Test ID")) + .addHeaderCell(getHeaderCell("Prio")) + .addHeaderCell(getHeaderCell("Application")); + if (displayCountryColumn) { + tableExe.addHeaderCell(getHeaderCell("Country")); + } + tableExe + .addHeaderCell(getHeaderCell("Environment")) + .addHeaderCell(getHeaderCell("Robot")) + .addHeaderCell(getHeaderCell("Started")) + .addHeaderCell(getHeaderCell("Ended")) + .addHeaderCell(getHeaderCell("Result")); + + Calendar calStart = Calendar.getInstance(); + Calendar calEnd = Calendar.getInstance(); + + int nbColSpan = 8; + if (displayCountryColumn) { + nbColSpan = 9; + } + + // Build Cerberus URL to execution. + String cerberusUrl = parameterService.getParameterStringByKey("cerberus_gui_url", "", ""); + if (StringUtil.isEmpty(cerberusUrl)) { + cerberusUrl = parameterService.getParameterStringByKey("cerberus_url", "", ""); + } + cerberusUrl = StringUtil.addSuffixIfNotAlready(cerberusUrl, "/"); + + int exe_count = 0; + int appendix_page = 0; + for (TestCaseExecution execution : listOfExecutions) { + appendix_page = (exe_count / NB_EXECUTION_PER_APPENDIX_FILE) + 1; + exe_count++; + Cell cellID = new Cell(2, 1) + .add(new Paragraph(String.valueOf(execution.getId())).setFontSize(8)).setVerticalAlignment(VerticalAlignment.MIDDLE).setTextAlignment(TextAlignment.CENTER) + .add(new Paragraph("appx " + appendix_page).setFontSize(6)).setVerticalAlignment(VerticalAlignment.MIDDLE).setTextAlignment(TextAlignment.CENTER); + Cell cellRes = getStatusCell(execution.getControlStatus(), 2, 1); + Cell cellTCDesc = new Cell(1, nbColSpan).add(new Paragraph(execution.getDescription())).setFontSize(7); + calStart.setTimeInMillis(execution.getStart()); + calEnd.setTimeInMillis(execution.getEnd()); + + tableExe + .addCell(cellID.setAction(PdfAction.createURI(cerberusUrl + "TestCaseExecution.jsp?executionId=" + String.valueOf(execution.getId())))) + .addCell(new Cell().add(new Paragraph(execution.getTest())).setFontSize(7)) + .addCell(new Cell().add(new Paragraph(execution.getTestCase())).setFontSize(7)) + .addCell(new Cell().add(new Paragraph(String.valueOf(execution.getTestCasePriority()))).setFontSize(7)) + .addCell(new Cell().add(new Paragraph(execution.getApplication())).setFontSize(7)); + if (displayCountryColumn) { + tableExe + .addCell(new Cell().add(new Paragraph(execution.getCountry())).setFontSize(7)); + } + tableExe + .addCell(new Cell().add(new Paragraph(execution.getEnvironment())).setFontSize(7)) + .addCell(new Cell().add(new Paragraph(execution.getRobot())).setFontSize(7)) + .addCell(new Cell().add(new Paragraph(df.format(calStart.getTime()))).setFontSize(7)) + .addCell(new Cell().add(new Paragraph(df.format(calEnd.getTime()))).setFontSize(7)) + .addCell(cellRes); + tableExe + .addCell(cellTCDesc); + } + document.add(tableExe); + document.add(aB); + + document.add(getTitleTable("Other technical details", "").setMarginLeft(0)); + + if (StringUtil.isEmptyOrNullValue(tag.getCampaign())) { + if (!StringUtil.isEmptyOrNullValue(tag.getUsrCreated())) { + document.add(new Paragraph() + .add(getTextFromString("Triggered by ", 10, false)) + .add(getTextFromString(tag.getUsrCreated(), 12, true)) + ); + } + } else { + if (StringUtil.isEmptyOrNullValue(tag.getUsrCreated())) { + document.add(new Paragraph() + .add(getTextFromString("Triggered from campaign: ", 10, false)) + .add(getTextFromString(tag.getCampaign(), 12, true)) + ); + } else { + document.add(new Paragraph() + .add(getTextFromString("Triggered from campaign: ", 10, false)) + .add(getTextFromString(tag.getCampaign(), 12, true)) + .add(getTextFromString(" by ", 10, false)) + .add(getTextFromString(tag.getUsrCreated(), 12, true)) + ); + } + } + + document.add(new Paragraph() + .add(getTextFromString("Global result for campaign is ", 10, false)) + .add(getTextFromString(tag.getCiResult(), 12, true)) + .add(getTextFromString(" (with a Score of ", 10, false)) + .add(getTextFromString(String.valueOf(tag.getCiScore()), 12, true)) + .add(getTextFromString(" vs ", 10, false)) + .add(getTextFromString(String.valueOf(tag.getCiScoreThreshold()), 12, true)) + .add(getTextFromString(")", 10, false))); + + document.add(new Paragraph() + .add(getTextFromString(String.valueOf(tag.getNbExeUsefull()), 12, true)) + .add(getTextFromString(" useful executions were performed (Over ", 10, false)) + .add(getTextFromString(String.valueOf(tag.getNbExe()), 12, true)) + .add(getTextFromString(" in total including retries)", 10, false))); + + /** + * Legend + */ + document.add(new Paragraph("Execution status legend").setMarginTop(30).setMarginBottom(10).setBold().setFontSize(14)); + // Creating a table + Table tableLegendGlobalStatus = new Table(new float[]{50, 500}) + .addHeaderCell(getHeaderCell("Status")) + .addHeaderCell(getHeaderCell("Meaning")); + tableLegendGlobalStatus + .addCell(getStatusCell(TestCaseExecution.CONTROLSTATUS_OK, 1, 1)) + .addCell("The execution was performed correctly and all controls were OK.").setTextAlignment(TextAlignment.LEFT) + .addCell(getStatusCell(TestCaseExecution.CONTROLSTATUS_KO, 1, 1)) + .addCell("The execution was performed correcly and at least one control failed resulting a global KO. That means that a bug needs to be reported to development teams.").setTextAlignment(TextAlignment.LEFT) + .addCell(getStatusCell(TestCaseExecution.CONTROLSTATUS_FA, 1, 1)) + .addCell("The execution did not performed correctly and needs a correction from the team that is in charge of managing the testcases. It could be a failed SQL or action during the test.").setTextAlignment(TextAlignment.LEFT) + .addCell(getStatusCell(TestCaseExecution.CONTROLSTATUS_NA, 1, 1)) + .addCell("Test could not be executed as a data could not be retreived. That probably means that the test is not possible in the current environment/status.").setTextAlignment(TextAlignment.LEFT); + + // Adding Table to document + document.add(tableLegendGlobalStatus); + + document.add(new Paragraph("Test cases legend").setMarginTop(30).setMarginBottom(10).setBold().setFontSize(14)); + + Table tableTmp; + + tableTmp = new Table(new float[]{500, 20}) + .addCell(new Cell().add(new Paragraph().add(getTextFromString("Step", 12, true).setTextAlignment(TextAlignment.LEFT))) + .setBorder(Border.NO_BORDER).setBorderLeft(new SolidBorder(ColorConstants.CYAN, 3)).setBorderRight(new SolidBorder(1)).setBorderTop(new SolidBorder(1)).setBorderBottom(new SolidBorder(1))) + .addCell(getStatusCell("OK", 1, 1).setTextAlignment(TextAlignment.RIGHT)); + document.add(tableTmp.setMarginLeft(0)); + + tableTmp = new Table(new float[]{500, 20}) + .addCell(new Cell().add(new Paragraph().add(getTextFromString("Action", 12, true).setTextAlignment(TextAlignment.LEFT))) + .setBorder(Border.NO_BORDER).setBorderLeft(new SolidBorder(ColorConstants.BLUE, 3)).setBorderRight(new SolidBorder(1)).setBorderTop(new SolidBorder(1)).setBorderBottom(new SolidBorder(1))) + .addCell(getStatusCell("OK", 1, 1).setTextAlignment(TextAlignment.RIGHT)); + document.add(tableTmp.setMarginLeft(20)); + + tableTmp = new Table(new float[]{500, 20}) + .addCell(new Cell().add(new Paragraph().add(getTextFromString("Control", 12, true).setTextAlignment(TextAlignment.LEFT))) + .setBorder(Border.NO_BORDER).setBorderLeft(new SolidBorder(ColorConstants.GREEN, 3)).setBorderRight(new SolidBorder(1)).setBorderTop(new SolidBorder(1)).setBorderBottom(new SolidBorder(1))) + .addCell(getStatusCell("OK", 1, 1).setTextAlignment(TextAlignment.RIGHT)); + document.add(tableTmp.setMarginLeft(40)); + + // Closing the document + LOG.info("Ending to generate PDF Report on :" + dest); + return dest; + } catch (ParseException | CerberusException | JSONException ex) { + LOG.error(ex, ex); + } catch (Exception ex) { + LOG.error(ex, ex); + } + return null; + } + + @Override + public List generatePdfAppendix(Tag tag, Date today, String folder) throws FileNotFoundException { + + List destList = new ArrayList<>(); + + UUID fileUUID = UUID.randomUUID(); + + // Load parameters + String mediaPath = parameterService.getParameterStringByKey(Parameter.VALUE_cerberus_exeautomedia_path, "", ""); + mediaPath = StringUtil.addSuffixIfNotAlready(mediaPath, File.separator); + + boolean displayCountryColumn = parameterService.getParameterBooleanByKey(Parameter.VALUE_cerberus_pdfcampaignreportdisplaycountry_boolean, "", true); + + /** + * Summary result per execution + */ + List listOfExecutions; + int total_nb_pages = 0; + try { + + // Getting and sorting list of executions. + listOfExecutions = testCaseExecutionService.readLastExecutionAndExecutionInQueueByTag(tag.getTag()); + Collections.sort(listOfExecutions, new SortExecution()); + + // Calculating total nb of pages. + total_nb_pages = (listOfExecutions.size() / NB_EXECUTION_PER_APPENDIX_FILE) + 1; + + int appendix_page; + boolean file_not_yet_created = false; + for (int current_appendix_index = 1; current_appendix_index < total_nb_pages + 1; current_appendix_index++) { + + // Creating a PdfWriter + String dest = folder + File.separatorChar + "Campaign Execution Report Appendix " + current_appendix_index + " tmp.pdf"; + destList.add(dest); + LOG.info("Starting to generate PDF Report on :" + dest); + PdfWriter writer = new PdfWriter(dest); + + // Creating a PdfDocument + PdfDocument pdfDoc = new PdfDocument(writer); + + try ( // Creating a Document + Document document = new Document(pdfDoc)) { + + AreaBreak aB = new AreaBreak(); + + // Tittle + document.add(getTitleTable("", "")); + + Table tableExe, tableTmp; + + tableTmp = new Table(new float[]{600}) + .addCell(new Cell().add(new Paragraph().add(getTextFromString("APPENDIX " + current_appendix_index + "/" + total_nb_pages, 20, true).setTextAlignment(TextAlignment.CENTER)).setTextAlignment(TextAlignment.CENTER)).setBorder(Border.NO_BORDER)); + document.add(tableTmp.setMarginTop(200)); + + tableTmp = new Table(new float[]{600}) + .addCell(new Cell().add(new Paragraph().add(getTextFromString("Details of Execution Campaign", 20, true).setTextAlignment(TextAlignment.CENTER)).setTextAlignment(TextAlignment.CENTER)).setBorder(Border.NO_BORDER)); + document.add(tableTmp.setMarginTop(40)); + + /** + * Detail information per execution + */ + int i = 0; + for (TestCaseExecution execution : listOfExecutions) { + appendix_page = (i / NB_EXECUTION_PER_APPENDIX_FILE) + 1; + + // We display the execution only if exe is on the correct appendix file. + if (appendix_page == current_appendix_index) { + + document.add(aB); + + document.add(new Paragraph("Execution: " + execution.getId()).setBold().setFontSize(20).setTextAlignment(TextAlignment.CENTER).setDestination(String.valueOf(execution.getId()))); + // Adding exeution details + String coloHex = getColor(execution.getControlStatus()); + document.add(new Paragraph(execution.getControlStatus() + " - " + execution.getDescription()) + .setBackgroundColor(new DeviceRgb(decodeColor(coloHex, "R"), decodeColor(coloHex, "G"), decodeColor(coloHex, "B")))); + document.add(new Paragraph() + .add(getTextFromString(String.valueOf(execution.getControlMessage()), 12, true))); + + if (displayCountryColumn) { + tableExe = new Table(new float[]{200, 90, 20, 70, 80, 70, 70}); + } else { + tableExe = new Table(new float[]{200, 90, 20, 70, 70, 70}); + } + tableExe + .addHeaderCell(getHeaderCell("Test Folder")) + .addHeaderCell(getHeaderCell("Test ID")) + .addHeaderCell(getHeaderCell("Prio")) + .addHeaderCell(getHeaderCell("Application")); + if (displayCountryColumn) { + tableExe + .addHeaderCell(getHeaderCell("Country")); + } + tableExe + .addHeaderCell(getHeaderCell("Environment")) + .addHeaderCell(getHeaderCell("Robot")); + tableExe + .addCell(execution.getTest()) + .addCell(execution.getTestCase()) + .addCell(String.valueOf(execution.getTestCasePriority())) + .addCell(execution.getApplication()); + if (displayCountryColumn) { + tableExe + .addCell(execution.getCountry()); + + } + tableExe + .addCell(execution.getEnvironment()) + .addCell(execution.getRobot()); + document.add(tableExe.setMarginTop(10).setMarginBottom(10)); + + @SuppressWarnings("unchecked") + TestCaseExecution exec = testCaseExecutionService.convert(testCaseExecutionService.readByKeyWithDependency(execution.getId())); + String desc = ""; + + for (TestCaseStepExecution step : exec.getTestCaseStepExecutionList()) { + if (!TestCaseExecution.CONTROLSTATUS_NE.equals(step.getReturnCode())) { + + // Creating a table + tableTmp = new Table(new float[]{500, 20}) + .addCell(new Cell().add(new Paragraph().add(getTextFromString(getElementDescription(step.getDescription(), step.getSort(), step.getIndex(), step.getTest()), 12, true).setTextAlignment(TextAlignment.LEFT))) + .setBorder(Border.NO_BORDER).setBorderLeft(new SolidBorder(ColorConstants.CYAN, 3)).setBorderRight(new SolidBorder(1)).setBorderTop(new SolidBorder(1)).setBorderBottom(new SolidBorder(1))) + .addCell(getStatusCell(step.getReturnCode(), 1, 1).setTextAlignment(TextAlignment.RIGHT)); + document.add(tableTmp.setMarginLeft(0).setMarginTop(20)); + + document.add(new Paragraph() + .add(getTextFromString(String.valueOf(step.getReturnMessage()), 10, false)) + .setMarginLeft(0) + ); + + // Add images is exist + tableTmp = getImageTable(step.getFileList(), mediaPath); + if (tableTmp != null) { + document.add(tableTmp.setMarginLeft(0)); + } + + } + + for (TestCaseStepActionExecution action : step.getTestCaseStepActionExecutionList()) { + if (!TestCaseExecution.CONTROLSTATUS_NE.equals(action.getReturnCode())) { + tableTmp = new Table(new float[]{500, 20}) + .addCell(new Cell().add(new Paragraph().add(getTextFromString(getElementDescription(action.getDescription(), action.getSort(), 0, action.getTest()), 12, true).setTextAlignment(TextAlignment.LEFT))) + .setBorder(Border.NO_BORDER).setBorderLeft(new SolidBorder(ColorConstants.BLUE, 3)).setBorderRight(new SolidBorder(1)).setBorderTop(new SolidBorder(1)).setBorderBottom(new SolidBorder(1))) + .addCell(getStatusCell(action.getReturnCode(), 1, 1).setTextAlignment(TextAlignment.RIGHT)); + document.add(tableTmp.setMarginLeft(20)); + + document.add(new Paragraph() + .add(getTextFromString(String.valueOf(action.getReturnMessage()), 10, false)) + .setMarginLeft(20) + ); + + // Add images is exist + tableTmp = getImageTable(action.getFileList(), mediaPath); + if (tableTmp != null) { + document.add(tableTmp.setMarginLeft(20)); + } + + } + + for (TestCaseStepActionControlExecution control : action.getTestCaseStepActionControlExecutionList()) { + + if (!TestCaseExecution.CONTROLSTATUS_NE.equals(control.getReturnCode())) { + tableTmp = new Table(new float[]{500, 20}) + .addCell(new Cell().add(new Paragraph().add(getTextFromString(getElementDescription(control.getDescription(), control.getSort(), 0, control.getTest()), 12, true).setTextAlignment(TextAlignment.LEFT))) + .setBorder(Border.NO_BORDER).setBorderLeft(new SolidBorder(ColorConstants.GREEN, 3)).setBorderRight(new SolidBorder(1)).setBorderTop(new SolidBorder(1)).setBorderBottom(new SolidBorder(1))) + .addCell(getStatusCell(control.getReturnCode(), 1, 1).setTextAlignment(TextAlignment.RIGHT)); + document.add(tableTmp.setMarginLeft(40)); + + document.add(new Paragraph() + .add(getTextFromString(String.valueOf(control.getReturnMessage()), 10, false)) + .setMarginLeft(40) + ); + + // Add images is exist + tableTmp = getImageTable(control.getFileList(), mediaPath); + if (tableTmp != null) { + document.add(tableTmp.setMarginLeft(40)); + } + } + + } + + } + + } + } + + i++; + } + + // Closing the document + LOG.info("Ending to generate PDF Report on :" + dest); + } catch (CerberusException ex) { + LOG.error(ex, ex); + } catch (Exception ex) { + LOG.error(ex, ex); + } + + } + + } catch (ParseException | CerberusException ex) { + LOG.error("Error when getting the list of execution for pdf file generation.", ex); + } catch (Exception ex) { + LOG.error(ex, ex); + } + + return destList; + } + + private String getElementDescription(String desc, int sort, int seq, String test) { + if (Test.TEST_PRETESTING.equals(test)) { + return "[PRE] " + desc; + } else if (Test.TEST_POSTTESTING.equals(test)) { + return "[POST] " + desc; + } else if (seq > 0) { + return "[" + sort + "." + seq + "] " + desc; + } else { + return "[" + sort + "] " + desc; + } + } + + @Override + public String addHeaderAndFooter(String pdfFilePathSrc, String destinationFile, Tag tag, Date today, boolean withLogo) throws FileNotFoundException { + try { + LOG.info("Starting to add Headers on PDF Report :" + pdfFilePathSrc + " To : " + destinationFile); + + String logoURL = parameterService.getParameterStringByKey(Parameter.VALUE_cerberus_instancelogo_url, "", "https://vm.cerberus-testing.org/img/logo.png"); + // Tittle + ImageData imageDataLogo; + if (StringUtil.isNotEmptyOrNullValue(logoURL)) { + imageDataLogo = ImageDataFactory.create(logoURL); + } else { + imageDataLogo = ImageDataFactory.create("https://vm.cerberus-testing.org/img/logo.png"); + } + Image image = new Image(imageDataLogo).scaleToFit(50, 70); + + DateFormat df = new SimpleDateFormat(DateUtil.DATE_FORMAT_REPORT); + + // Adding Headers and Footers + Paragraph headerRight = new Paragraph("Campaign Execution Report - " + tag.getTag()) + .setFontSize(5).setItalic().setTextAlignment(TextAlignment.RIGHT).setWidth(400); + Paragraph headerLeft = new Paragraph() + .setFontSize(5).setItalic().add(image); + + PdfDocument pdfDoc = new PdfDocument(new PdfReader(pdfFilePathSrc), new PdfWriter(destinationFile)); + Document doc = new Document(pdfDoc); + for (int i = 1; i <= pdfDoc.getNumberOfPages(); i++) { + + Rectangle pageSize = pdfDoc.getPage(i).getPageSize(); + PdfPage curPage = pdfDoc.getPage(i); + + // Header insert (no header on first page) +// if (i != 1) { + LOG.debug("headerRight x " + pageSize.getWidth() + " y " + (pageSize.getTop() - 20)); + doc.showTextAligned(headerRight, 570, pageSize.getTop() - 20, i, TextAlignment.RIGHT, VerticalAlignment.TOP, 0); + // Logo is always displayed on 1st page. It is displayed on other page only if logo flag is activated. + if (withLogo || i == 1) { + LOG.debug("headerLeft x " + (20) + " y " + (pageSize.getTop() - 20)); + doc.showTextAligned(headerLeft, 20, pageSize.getTop() - 40, i, TextAlignment.LEFT, VerticalAlignment.BOTTOM, 0); + + } +// } + + // Footer insert + Paragraph footerRight = new Paragraph("Page " + i + " / " + pdfDoc.getNumberOfPages()) + .setFontSize(5).setItalic(); + Paragraph footerLeft = new Paragraph("(C) Cerberus Testing - " + df.format(today)) + .setFontSize(5).setItalic(); + + doc.showTextAligned(footerRight, pageSize.getRight() - 60, pageSize.getBottom() + 20, i, TextAlignment.LEFT, VerticalAlignment.BOTTOM, 0); + doc.showTextAligned(footerLeft, 20, pageSize.getBottom() + 20, i, TextAlignment.LEFT, VerticalAlignment.BOTTOM, 0); + + } + doc.close(); + LOG.info("Ended to add Headers on PDF Report :" + pdfFilePathSrc + " To : " + destinationFile); + + } catch (IOException ex) { + LOG.error(ex, ex); + } + return destinationFile; + + } + + private Text getTextFromString(String text, int fontSize, boolean isBold) { + if (isBold) { + return new Text(text).setBold().setFontSize(fontSize); + + } else { + return new Text(text).setFontSize(fontSize); + + } + } + + private Table getImageTable(List fileList, String mediaPath) { + Table tableTmp = null; + boolean imageInserted = false; + // We count the nb of images in the file list. + int nbImages = 0; + for (TestCaseExecutionFile exeFile : fileList) { + if (exeFile.isImage() && !exeFile.getFileDesc().contains("Picture")) { + nbImages++; + } + } + + // If there is at least 1 image in the list + if (nbImages > 0) { + tableTmp = new Table(new float[]{150, 500}); + + imageInserted = false; + for (TestCaseExecutionFile controlFile : fileList) { + + if (controlFile.isImage() && !imageInserted) { + // Load screenshots to pdf. + ImageData imageData; + try { + File f = new File(mediaPath + controlFile.getFileName()); + imageInserted = true; + if (f.exists()) { + imageData = ImageDataFactory.create(mediaPath + controlFile.getFileName()); + Image image = new Image(imageData).scaleToFit(500, 200); + tableTmp.addCell(new Cell().add(new Paragraph().add(getTextFromString(controlFile.getFileDesc(), 7, false)).setTextAlignment(TextAlignment.LEFT)) + .setBorder(Border.NO_BORDER).setVerticalAlignment(VerticalAlignment.MIDDLE)) + .addCell(new Cell().add(image.setBorder(Border.NO_BORDER).setHorizontalAlignment(HorizontalAlignment.RIGHT)).setBorder(Border.NO_BORDER)); + + } else { + tableTmp.addCell(new Cell().add(new Paragraph().add(getTextFromString(controlFile.getFileDesc(), 7, false)).setTextAlignment(TextAlignment.LEFT)) + .setBorder(Border.NO_BORDER).setVerticalAlignment(VerticalAlignment.MIDDLE)) + .addCell(new Cell().add(new Paragraph().add(getTextFromString("File no longuer exist !!!", 7, false)).setTextAlignment(TextAlignment.RIGHT)).setBorder(Border.NO_BORDER)); + } + } catch (MalformedURLException ex) { + LOG.error(ex, ex); + } catch (Exception ex) { + LOG.error(ex, ex); + } + } + + } + + } + + return tableTmp; + } + + class SortExecution implements Comparator { + // Used for sorting in ascending order of + // Label name. + + @Override + public int compare(TestCaseExecution a, TestCaseExecution b) { + if (a != null && b != null) { +// int aPrio = a.getTestCasePriority(); +// if (a.getTestCasePriority() < 1 || a.getTestCasePriority() > 5) { +// aPrio = 999 + a.getTestCasePriority(); +// } +// int bPrio = b.getTestCasePriority(); +// if (b.getTestCasePriority() < 1 || b.getTestCasePriority() > 5) { +// bPrio = 999 + b.getTestCasePriority(); +// } + +// if (aPrio == bPrio) { + if (a.getTest().equals(b.getTest())) { + if (a.getTestCase().equals(b.getTestCase())) { + if (a.getEnvironment().equals(b.getEnvironment())) { + if (a.getCountry().equals(b.getCountry())) { + return a.getRobotDecli().compareToIgnoreCase(b.getRobotDecli()); + } else { + return a.getCountry().compareToIgnoreCase(b.getCountry()); + } + } else { + return a.getEnvironment().compareToIgnoreCase(b.getEnvironment()); + } + } else { + return a.getTestCase().compareToIgnoreCase(b.getTestCase()); + } + } else { + return a.getTest().compareToIgnoreCase(b.getTest()); + } +// } else { +// return aPrio - bPrio; +// } + } else { + return 1; + } + } + } + + private Cell getHeaderCell(String text) { + return new Cell().add(new Paragraph(text)).setBackgroundColor(ColorConstants.LIGHT_GRAY).setFontSize(8).setTextAlignment(TextAlignment.CENTER); + } + + private Cell getStatusCell(String status, int rowspan, int colspan) { + String coloHex = getColor(status); + + Cell cellRes = new Cell(rowspan, colspan) + .add(new Paragraph(status)) + .setBackgroundColor(new DeviceRgb(decodeColor(coloHex, "R"), decodeColor(coloHex, "G"), decodeColor(coloHex, "B"))) + .setVerticalAlignment(VerticalAlignment.MIDDLE) + .setTextAlignment(TextAlignment.CENTER); + + return cellRes; + } + + private int decodeColor(String hexColor, String indexRGB) { + String hexValue = hexColor.replace("#", "0x"); + + int i = Integer.decode(hexValue).intValue(); + switch (indexRGB) { + case "R": + return (i >> 16) & 0xFF; + case "G": + return (i >> 8) & 0xFF; + case "B": + return i & 0xFF; + } + + return 0; + } + + private String getColor(String controlStatus) { + String color = null; + + if ("OK".equals(controlStatus)) { + color = TestCaseExecution.CONTROLSTATUS_OK_COL_EXT; + } else if ("KO".equals(controlStatus)) { + color = TestCaseExecution.CONTROLSTATUS_KO_COL_EXT; + } else if ("FA".equals(controlStatus)) { + color = TestCaseExecution.CONTROLSTATUS_FA_COL_EXT; + } else if ("CA".equals(controlStatus)) { + color = TestCaseExecution.CONTROLSTATUS_CA_COL_EXT; + } else if ("NA".equals(controlStatus)) { + color = TestCaseExecution.CONTROLSTATUS_NA_COL_EXT; + } else if ("NE".equals(controlStatus)) { + color = TestCaseExecution.CONTROLSTATUS_NE_COL_EXT; + } else if ("WE".equals(controlStatus)) { + color = TestCaseExecution.CONTROLSTATUS_WE_COL_EXT; + } else if ("PE".equals(controlStatus)) { + color = TestCaseExecution.CONTROLSTATUS_PE_COL_EXT; + } else if ("QU".equals(controlStatus)) { + color = TestCaseExecution.CONTROLSTATUS_QU_COL_EXT; + } else if ("QE".equals(controlStatus)) { + color = TestCaseExecution.CONTROLSTATUS_QE_COL_EXT; + } else { + color = "#000000"; + } + return color; + } + +} diff --git a/source/src/main/java/org/cerberus/core/service/rest/impl/RestService.java b/source/src/main/java/org/cerberus/core/service/rest/impl/RestService.java index 6761749852..0c151a674c 100644 --- a/source/src/main/java/org/cerberus/core/service/rest/impl/RestService.java +++ b/source/src/main/java/org/cerberus/core/service/rest/impl/RestService.java @@ -143,7 +143,7 @@ private AppService executeHTTPCall(CloseableHttpClient httpclient, HttpRequestBa // Create a custom response handler ResponseHandler responseHandler = (final HttpResponse response) -> { AppService myResponse = factoryAppService.create("", AppService.TYPE_REST, - AppService.METHOD_HTTPGET, "", "", "", "", "", "", "", "", "", "", "", true, "", "", false, "", "", null, "", null, "", null, null); + AppService.METHOD_HTTPGET, "", "", "", "", "", "", "", "", "", "", "", true, "", "", false, "", false, "", false, "", null, "", null, "", null, null); int responseCode = response.getStatusLine().getStatusCode(); myResponse.setResponseHTTPCode(responseCode); myResponse.setResponseHTTPVersion(response.getProtocolVersion().toString()); @@ -172,7 +172,7 @@ public AnswerItem callREST(String servicePath, String requestString, List headerList, List contentList, String token, int timeOutMs, String system, boolean isFollowRedir, TestCaseExecution tcexecution) { AnswerItem result = new AnswerItem<>(); - AppService serviceREST = factoryAppService.create("", AppService.TYPE_REST, method, "", "", "", "", "", "", "", "", "", "", "", true, "", "", false, "", "", null, + AppService serviceREST = factoryAppService.create("", AppService.TYPE_REST, method, "", "", "", "", "", "", "", "", "", "", "", true, "", "", false, "", false, "", false, "", null, "", null, "", null, null); serviceREST.setProxy(false); serviceREST.setProxyHost(null); diff --git a/source/src/main/java/org/cerberus/core/service/soap/impl/SoapService.java b/source/src/main/java/org/cerberus/core/service/soap/impl/SoapService.java index 01cc50f72b..5f668d4dd3 100644 --- a/source/src/main/java/org/cerberus/core/service/soap/impl/SoapService.java +++ b/source/src/main/java/org/cerberus/core/service/soap/impl/SoapService.java @@ -208,7 +208,7 @@ public AnswerItem callSOAP(String envelope, String servicePath, Stri String unescapedEnvelope = StringEscapeUtils.unescapeXml(envelope); boolean is12SoapVersion = SOAP_1_2_NAMESPACE_PATTERN.matcher(unescapedEnvelope).matches(); - AppService serviceSOAP = factoryAppService.create("", AppService.TYPE_SOAP, null, "", "", envelope, "", "", "", "", "", "", "", servicePath, true, "", soapOperation, false, "", "", null, "", null, "", null, null); + AppService serviceSOAP = factoryAppService.create("", AppService.TYPE_SOAP, null, "", "", envelope, "", "", "", "", "", "", "", servicePath, true, "", soapOperation, false, "", false, "", false, "", null, "", null, "", null, null); serviceSOAP.setTimeoutms(timeOutMs); ByteArrayOutputStream out = null; MessageEvent message = null; diff --git a/source/src/main/java/org/cerberus/core/service/webdriver/IWebDriverService.java b/source/src/main/java/org/cerberus/core/service/webdriver/IWebDriverService.java index 8c08b07416..88a7a088f5 100644 --- a/source/src/main/java/org/cerberus/core/service/webdriver/IWebDriverService.java +++ b/source/src/main/java/org/cerberus/core/service/webdriver/IWebDriverService.java @@ -51,6 +51,10 @@ public interface IWebDriverService { boolean isElementNotVisible(Session session, Identifier identifier); + boolean isElementChecked(Session session, Identifier identifier); + + boolean isElementNotChecked(Session session, Identifier identifier); + boolean isElementInElement(Session session, Identifier identifier, Identifier childIdentifier); boolean isElementNotClickable(Session session, Identifier identifier); diff --git a/source/src/main/java/org/cerberus/core/service/webdriver/impl/WebDriverService.java b/source/src/main/java/org/cerberus/core/service/webdriver/impl/WebDriverService.java index 080d9a6e7c..d1bbe30006 100644 --- a/source/src/main/java/org/cerberus/core/service/webdriver/impl/WebDriverService.java +++ b/source/src/main/java/org/cerberus/core/service/webdriver/impl/WebDriverService.java @@ -206,13 +206,15 @@ private WebElement getWebElementUsingQuerySelector(Session session, String query public MessageEvent scrollTo(Session session, Identifier identifier, String text) { MessageEvent message = null; WebElement webElement = null; - try { if (StringUtil.isEmpty(text)) { AnswerItem answer = this.getSeleniumElement(session, identifier, false, false); if (answer.isCodeEquals(MessageEventEnum.ACTION_SUCCESS_WAIT_ELEMENT.getCode())) { webElement = (WebElement) answer.getItem(); + } else { + return answer.getResultMessage(); } + } else { webElement = session.getDriver().findElement(By.xpath("//*[contains(text()," + text + ")]")); } @@ -231,7 +233,11 @@ public MessageEvent scrollTo(Session session, Identifier identifier, String text } catch (NoSuchElementException exception) { message = new MessageEvent(MessageEventEnum.ACTION_FAILED_SCROLL_NO_SUCH_ELEMENT); - message.setDescription(message.getDescription().replace("%ELEMENT%", identifier.getIdentifier() + "=" + identifier.getLocator())); + if (StringUtil.isEmpty(text)) { + message.setDescription(message.getDescription().replace("%ELEMENT%", identifier.getIdentifier() + "=" + identifier.getLocator())); + } else { + message.setDescription(message.getDescription().replace("%ELEMENT%", "'" + text + "' (by text)")); + } LOG.debug(exception.toString()); return message; } catch (Exception e) { @@ -592,6 +598,36 @@ public boolean isElementNotVisible(Session session, Identifier identifier) { } } + @Override + public boolean isElementChecked(Session session, Identifier identifier) { + try { + AnswerItem answer = this.getSeleniumElement(session, identifier, true, false); + if (answer.isCodeEquals(MessageEventEnum.ACTION_SUCCESS_WAIT_ELEMENT.getCode())) { + WebElement webElement = (WebElement) answer.getItem(); + return webElement != null && webElement.isSelected(); + } + + } catch (NoSuchElementException exception) { + LOG.warn(exception.toString()); + } + return false; + } + + @Override + public boolean isElementNotChecked(Session session, Identifier identifier) { + try { + AnswerItem answer = this.getSeleniumElement(session, identifier, true, false); + if (answer.isCodeEquals(MessageEventEnum.ACTION_SUCCESS_WAIT_ELEMENT.getCode())) { + WebElement webElement = (WebElement) answer.getItem(); + return webElement != null && !webElement.isSelected(); + } + + } catch (NoSuchElementException exception) { + LOG.warn(exception.toString()); + } + return false; + } + @Override public String getPageSource(Session session) { return session.getDriver().getPageSource(); @@ -609,7 +645,7 @@ public String getTitle(Session session) { * @param applicationUrl * @return current URL without HTTP://IP:PORT/CONTEXTROOT/ * @throws CerberusEventException Cannot find application host (from - * Database) inside current URL (from Selenium) + * Database) inside current URL (from Selenium) */ @Override public String getCurrentUrl(Session session, String applicationUrl) throws CerberusEventException { @@ -799,11 +835,13 @@ public MessageEvent doSeleniumActionClick(Session session, final Identifier iden } return answer.getResultMessage(); + } catch (NoSuchElementException exception) { message = new MessageEvent(MessageEventEnum.ACTION_FAILED_CLICK_NO_SUCH_ELEMENT); message.setDescription(message.getDescription().replace("%ELEMENT%", identifier.getIdentifier() + "=" + identifier.getLocator())); LOG.debug(exception.toString()); return message; + } catch (WebDriverException exception) { LOG.warn(exception.toString()); return parseWebDriverException(exception); @@ -1018,23 +1056,31 @@ private boolean checkIfExpectedWindow(Session session, String identifier, String String title; switch (identifier) { - case Identifier.IDENTIFIER_URL: { - + case Identifier.IDENTIFIER_URL: wait.until(ExpectedConditions.not(ExpectedConditions.urlToBe("about:blank"))); - return session.getDriver().getCurrentUrl().equals(value); - } + result = session.getDriver().getCurrentUrl().equals(value); + break; + case Identifier.IDENTIFIER_REGEXURL: + wait.until(ExpectedConditions.not(ExpectedConditions.urlToBe("about:blank"))); + String currentUrl = session.getDriver().getCurrentUrl(); + Pattern patternUrl = Pattern.compile(value); + Matcher matcherUrl = patternUrl.matcher(currentUrl); + result = matcherUrl.find(); + break; case Identifier.IDENTIFIER_REGEXTITLE: wait.until(ExpectedConditions.not(ExpectedConditions.titleIs(""))); title = session.getDriver().getTitle(); Pattern pattern = Pattern.compile(value); Matcher matcher = pattern.matcher(title); result = matcher.find(); + break; default: wait.until(ExpectedConditions.not(ExpectedConditions.titleIs(""))); title = session.getDriver().getTitle(); if (title.equals(value)) { result = true; } + break; } return result; } @@ -1252,13 +1298,13 @@ public boolean focusBrowserWindow(Session session) { // Arbitrary String[] browsers = new String[]{ - "", - "Google Chrome", - "Mozilla Firefox", - "Opera", - "Safari", - "Internet Explorer", - "Microsoft Edge",}; + "", + "Google Chrome", + "Mozilla Firefox", + "Opera", + "Safari", + "Internet Explorer", + "Microsoft Edge",}; for (String browser : browsers) { HWND window; diff --git a/source/src/main/java/org/cerberus/core/service/xray/impl/XRayGenerationService.java b/source/src/main/java/org/cerberus/core/service/xray/impl/XRayGenerationService.java index 93222f0bdb..66c62b184b 100644 --- a/source/src/main/java/org/cerberus/core/service/xray/impl/XRayGenerationService.java +++ b/source/src/main/java/org/cerberus/core/service/xray/impl/XRayGenerationService.java @@ -23,6 +23,7 @@ import java.net.URLEncoder; import java.sql.Timestamp; import java.text.SimpleDateFormat; +import org.cerberus.core.crud.entity.Parameter; import org.cerberus.core.crud.entity.Tag; import org.cerberus.core.crud.entity.TestCase; import org.cerberus.core.crud.entity.TestCaseExecution; @@ -68,19 +69,27 @@ public JSONObject generateCreateTestExecution(Tag tag, TestCaseExecution executi infoMessage.put("description", tag.getDescription()); infoMessage.put("startDate", convertToDate(tag.getDateCreated())); - JSONArray environments = new JSONArray(); - environments.put(execution.getEnvironment()); - environments.put(execution.getCountry()); - if (execution.getRobotObj() != null) { - environments.put(execution.getRobotObj().getRobotDecli()); + // Adding Environments + if (parameterService.getParameterBooleanByKey(Parameter.VALUE_cerberus_xray_sendenvironments_enable, execution.getSystem(), false)) { + JSONArray environments = new JSONArray(); + if (StringUtil.isNotEmpty(execution.getEnvironment())) { + environments.put(execution.getEnvironment()); + } + if (StringUtil.isNotEmpty(execution.getCountry())) { + environments.put(execution.getCountry()); + } + if (execution.getRobotObj() != null) { + environments.put(execution.getRobotObj().getRobotDecli()); + } + infoMessage.put("testEnvironments", environments); } - infoMessage.put("testEnvironments", environments); xRayMessage.put("info", infoMessage); JSONArray testsMessage = new JSONArray(); JSONObject testMessage = new JSONObject(); testMessage.put("testKey", execution.getTestCaseObj().getRefOrigine()); + testMessage.put("start", convertToDate(execution.getStart())); testMessage.put("finish", convertToDate(execution.getEnd())); testMessage.put("comment", execution.getId() + " - " + execution.getControlMessage()); diff --git a/source/src/main/java/org/cerberus/core/service/xray/impl/XRayService.java b/source/src/main/java/org/cerberus/core/service/xray/impl/XRayService.java index b8311b8501..50a992b3ee 100644 --- a/source/src/main/java/org/cerberus/core/service/xray/impl/XRayService.java +++ b/source/src/main/java/org/cerberus/core/service/xray/impl/XRayService.java @@ -23,6 +23,7 @@ import java.net.URL; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; +import java.time.LocalDateTime; import java.util.HashMap; import java.util.Map; import javax.net.ssl.SSLContext; @@ -98,10 +99,12 @@ public class XRayService implements IXRayService { private static final String XRAYCLOUD_TESTEXECUTIONCREATION_URL = "https://xray.cloud.getxray.app/api/v2/import/execution"; private static final String XRAYDC_TESTEXECUTIONCREATION_URLPATH = "/rest/raven/2.0/api/import/execution"; + private static final int DEFAULT_XRAY_CACHE_DURATION = 300; + private String getToken(String system, String origin) { try { - if (cacheEntry.get("TOKEN-" + origin + "#" + system) != null) { - return cacheEntry.get("TOKEN-" + origin + "#" + system).getString("value"); + if (cacheEntry.containsKey(getCacheKey(origin, system))) { + return cacheEntry.get(getCacheKey(origin, system)).getString("value"); } } catch (JSONException ex) { LOG.error(ex, ex); @@ -111,11 +114,13 @@ private String getToken(String system, String origin) { private void putToken(String system, String origin, String value) { try { + LocalDateTime currentTime = LocalDateTime.now(); + JSONObject entry = new JSONObject(); - entry.put("key", "TOKEN-" + origin + "#" + system); + entry.put("key", getCacheKey(origin, system)); entry.put("value", value); - entry.put("created", "now"); - cacheEntry.put("TOKEN-" + origin + "#" + system, entry); + entry.put("created", currentTime.toString()); + cacheEntry.put(getCacheKey(origin, system), entry); } catch (JSONException ex) { LOG.error(ex, ex); } @@ -244,10 +249,9 @@ public boolean isTrusted(X509Certificate[] chain, String authType) throws Certif post.setHeader("Content-type", "application/json"); post.setHeader("Authorization", "Bearer " + getToken(execution.getSystem(), execution.getTestCaseObj().getOrigine())); - LOG.debug("Bearer " + getToken(execution.getSystem(), execution.getTestCaseObj().getOrigine())); - try { + LOG.debug("Calling {} with Bearer {}", xRayUrl, getToken(execution.getSystem(), execution.getTestCaseObj().getOrigine())); HttpResponse response = httpclient.execute(post); int rc = response.getStatusLine().getStatusCode(); @@ -274,7 +278,12 @@ public boolean isTrusted(X509Certificate[] chain, String authType) throws Certif } else { LOG.warn("XRay Test Execution request http return code : {} is missing 'key' entry.", rc); String responseString1 = EntityUtils.toString(response.getEntity()); - logEventService.createForPrivateCalls("XRAY", "APICALL", "Xray Execution creation request to '" + xRayUrl + "' failed with http return code : " + rc + ". and no 'key' entry. " + responseString1); + String message = "Xray Execution creation request to '" + xRayUrl + "' failed with http return code : " + rc + ". and no 'key' entry. " + responseString1; + logEventService.createForPrivateCalls("XRAY", "APICALL", message); + currentTag.setXRayURL(""); + currentTag.setXRayTestExecution("ERROR"); + currentTag.setXRayMessage(message); + tagService.updateXRayTestExecution(currentTag.getTag(), currentTag); LOG.warn("Message sent to " + xRayUrl + " :"); LOG.warn(xRayRequest.toString(1)); LOG.warn("Response : {}", responseString1); @@ -282,7 +291,12 @@ public boolean isTrusted(X509Certificate[] chain, String authType) throws Certif } else { LOG.warn("XRay Test Execution request http return code : " + rc); String responseString = EntityUtils.toString(response.getEntity()); - logEventService.createForPrivateCalls("XRAY", "APICALL", "Xray Execution creation request to '" + xRayUrl + "' failed with http return code : " + rc + ". " + responseString); + String message = "Xray Execution creation request to '" + xRayUrl + "' failed with http return code : " + rc + ". " + responseString; + logEventService.createForPrivateCalls("XRAY", "APICALL", message); + currentTag.setXRayURL(""); + currentTag.setXRayTestExecution("ERROR"); + currentTag.setXRayMessage(message); + tagService.updateXRayTestExecution(currentTag.getTag(), currentTag); LOG.warn("Message sent to " + xRayUrl + " :"); LOG.warn(xRayRequest.toString(1)); LOG.warn("Response : {}", responseString); @@ -305,11 +319,11 @@ public boolean isTrusted(X509Certificate[] chain, String authType) throws Certif private void getXRayAuthenticationToken(String origin, String system) throws Exception { String xRayUrl = XRAYCLOUD_AUTHENT_URL; - if (getToken(system, origin) == null) { + if (getToken(system, origin) == null || (isTokenExpired(origin, system))) { if (TestCase.TESTCASE_ORIGIN_JIRAXRAYCLOUD.equals(origin)) { - LOG.debug("Getting new XRay Token."); + LOG.debug("Getting new XRay Token for {} and {}.", system, origin); String clientID = parameterService.getParameterStringByKey(Parameter.VALUE_cerberus_xraycloud_clientid, system, ""); String clientSecret = parameterService.getParameterStringByKey(Parameter.VALUE_cerberus_xraycloud_clientsecret, system, ""); @@ -415,4 +429,29 @@ public boolean isTrusted(X509Certificate[] chain, String authType) throws Certif } + private boolean isTokenExpired(String origin, String system) { + try { + LOG.debug("Checking Token Cache validity."); + LocalDateTime currentTime = LocalDateTime.now(); + int cacheDuration = parameterService.getParameterIntegerByKey(Parameter.VALUE_cerberus_xray_tokencache_duration, system, DEFAULT_XRAY_CACHE_DURATION); + if (cacheEntry.containsKey(getCacheKey(origin, system))) { + LOG.debug("Cache entry creation timestamp {}", cacheEntry.get(getCacheKey(origin, system)).getString("created")); + LocalDateTime cacheDateTime = LocalDateTime.parse(cacheEntry.get(getCacheKey(origin, system)).getString("created")); + LOG.debug("isTokenExpired : {}", cacheDateTime.plusSeconds(cacheDuration).isBefore(currentTime)); + return cacheDateTime.plusSeconds(cacheDuration).isBefore(currentTime); + } else { + LOG.debug("isTokenExpired (no entry found) : {}", true); + return true; + } + } catch (JSONException ex) { + LOG.error(ex, ex); + } + + return true; + } + + private String getCacheKey(String origin, String system) { + return "TOKEN-" + origin + "#" + system; + } + } diff --git a/source/src/main/java/org/cerberus/core/servlet/crud/countryenvironment/CreateAppService.java b/source/src/main/java/org/cerberus/core/servlet/crud/countryenvironment/CreateAppService.java index f7c0b0657d..1c2e4f0612 100644 --- a/source/src/main/java/org/cerberus/core/servlet/crud/countryenvironment/CreateAppService.java +++ b/source/src/main/java/org/cerberus/core/servlet/crud/countryenvironment/CreateAppService.java @@ -140,7 +140,10 @@ final void processRequest(final HttpServletRequest request, final HttpServletRes String kafkaTopic = ParameterParserUtil.parseStringParamAndDecode(fileData.get("kafkaTopic"), "", charset); boolean isAvroEnable = ParameterParserUtil.parseBooleanParamAndDecode(fileData.get("isAvroEnable"), true, charset); String schemaRegistryUrl = ParameterParserUtil.parseStringParamAndDecode(fileData.get("schemaRegistryUrl"), null, charset); - String avroSchema = ParameterParserUtil.parseStringParamAndDecode(fileData.get("avroSchema"), null, charset); + boolean isAvroEnableKey = ParameterParserUtil.parseBooleanParamAndDecode(fileData.get("isAvroEnableKey"), true, charset); + String avroSchemaKey = ParameterParserUtil.parseStringParamAndDecode(fileData.get("avrSchemaKey"), null, charset); + boolean isAvroEnableValue = ParameterParserUtil.parseBooleanParamAndDecode(fileData.get("isAvroEnableValue"), true, charset); + String avroSchemaValue = ParameterParserUtil.parseStringParamAndDecode(fileData.get("avrSchemaValue"), null, charset); String parentContentService = ParameterParserUtil.parseStringParamAndDecode(fileData.get("parentContentService"), "", charset); String kafkaKey = ParameterParserUtil.parseStringParamAndDecode(fileData.get("kafkaKey"), "", charset); String kafkaFilterPath = ParameterParserUtil.parseStringParamAndDecode(fileData.get("kafkaFilterPath"), "", charset); @@ -178,7 +181,7 @@ final void processRequest(final HttpServletRequest request, final HttpServletRes appServiceHeaderFactory = appContext.getBean(IFactoryAppServiceHeader.class); LOG.debug(request.getUserPrincipal().getName()); AppService appService = appServiceFactory.create(service, type, method, application, group, serviceRequest, kafkaTopic, kafkaKey, kafkaFilterPath, kafkaFilterValue, kafkaFilterHeaderPath, kafkaFilterHeaderValue, description, servicePath, - isFollowRedir, attachementurl, operation, isAvroEnable, schemaRegistryUrl, avroSchema, parentContentService, request.getUserPrincipal().getName(), null, null, null, fileName); + isFollowRedir, attachementurl, operation, isAvroEnable, schemaRegistryUrl, isAvroEnableKey, avroSchemaKey, isAvroEnableValue, avroSchemaValue, parentContentService, request.getUserPrincipal().getName(), null, null, null, fileName); ans = appServiceService.create(appService); finalAnswer = AnswerUtil.agregateAnswer(finalAnswer, ans); diff --git a/source/src/main/java/org/cerberus/core/servlet/crud/countryenvironment/UpdateAppService.java b/source/src/main/java/org/cerberus/core/servlet/crud/countryenvironment/UpdateAppService.java index d5f83be569..f3836d8e8c 100644 --- a/source/src/main/java/org/cerberus/core/servlet/crud/countryenvironment/UpdateAppService.java +++ b/source/src/main/java/org/cerberus/core/servlet/crud/countryenvironment/UpdateAppService.java @@ -140,7 +140,10 @@ final void processRequest(final HttpServletRequest request, final HttpServletRes String kafkaTopic = ParameterParserUtil.parseStringParamAndDecode(fileData.get("kafkaTopic"), "", charset); boolean isAvroEnable = ParameterParserUtil.parseBooleanParam(fileData.get("isAvroEnable"), false); String schemaRegistryUrl = ParameterParserUtil.parseStringParamAndDecode(fileData.get("schemaRegistryUrl"), null, charset); - String avrSchema = ParameterParserUtil.parseStringParamAndDecode(fileData.get("avrSchema"), null, charset); + boolean isAvroEnableKey = ParameterParserUtil.parseBooleanParam(fileData.get("isAvroEnableKey"), false); + String avrSchemaKey = ParameterParserUtil.parseStringParamAndDecode(fileData.get("avrSchemaKey"), null, charset); + boolean isAvroEnableValue = ParameterParserUtil.parseBooleanParam(fileData.get("isAvroEnableValue"), false); + String avrSchemaValue = ParameterParserUtil.parseStringParamAndDecode(fileData.get("avrSchemaValue"), null, charset); String parentContentService = ParameterParserUtil.parseStringParamAndDecode(fileData.get("parentContentService"), "", charset); String kafkaKey = ParameterParserUtil.parseStringParamAndDecode(fileData.get("kafkaKey"), "", charset); String kafkaFilterPath = ParameterParserUtil.parseStringParamAndDecode(fileData.get("kafkaFilterPath"), "", charset); @@ -215,8 +218,11 @@ final void processRequest(final HttpServletRequest request, final HttpServletRes appService.setKafkaFilterHeaderValue(kafkaFilterHeaderValue); appService.setFollowRedir(isFollowRedir); appService.setAvroEnable(isAvroEnable); + appService.setAvroEnableKey(isAvroEnableKey); + appService.setAvroEnableValue(isAvroEnableValue); appService.setSchemaRegistryURL(schemaRegistryUrl); - appService.setAvroSchema(avrSchema); + appService.setAvroSchemaKey(avrSchemaKey); + appService.setAvroSchemaValue(avrSchemaValue); appService.setParentContentService(parentContentService); ans = appServiceService.update(originalService, appService); diff --git a/source/src/main/java/org/cerberus/core/servlet/crud/testexecution/CreateRobot.java b/source/src/main/java/org/cerberus/core/servlet/crud/testexecution/CreateRobot.java index 0711ab42ae..a881142d08 100644 --- a/source/src/main/java/org/cerberus/core/servlet/crud/testexecution/CreateRobot.java +++ b/source/src/main/java/org/cerberus/core/servlet/crud/testexecution/CreateRobot.java @@ -108,7 +108,7 @@ protected void processRequest(HttpServletRequest request, HttpServletResponse re String robotDecli = ParameterParserUtil.parseStringParamAndDecode(request.getParameter("robotDecli"), "", charset); String lbexemethod = ParameterParserUtil.parseStringParamAndDecodeAndSanitize(request.getParameter("lbexemethod"), "", charset); String type = ParameterParserUtil.parseStringParamAndDecodeAndSanitize(request.getParameter("type"), "", charset); - String extraParam = ParameterParserUtil.parseStringParamAndDecodeAndSanitize(request.getParameter("extraParam"), "", charset); + String extraParam = ParameterParserUtil.parseStringParamAndDecode(request.getParameter("extraParam"), "", charset); boolean isAcceptInsecureCerts = ParameterParserUtil.parseBooleanParamAndDecode(request.getParameter("isAcceptInsecureCerts"), true, charset); List capabilities; diff --git a/source/src/main/java/org/cerberus/core/servlet/crud/testexecution/UpdateRobot.java b/source/src/main/java/org/cerberus/core/servlet/crud/testexecution/UpdateRobot.java index dd3a3c03ca..9e63c62dc7 100644 --- a/source/src/main/java/org/cerberus/core/servlet/crud/testexecution/UpdateRobot.java +++ b/source/src/main/java/org/cerberus/core/servlet/crud/testexecution/UpdateRobot.java @@ -106,7 +106,7 @@ protected void processRequest(HttpServletRequest request, HttpServletResponse re String robotDecli = ParameterParserUtil.parseStringParamAndDecode(request.getParameter("robotDecli"), null, charset); String lbexemethod = ParameterParserUtil.parseStringParamAndDecodeAndSanitize(request.getParameter("lbexemethod"), null, charset); String type = ParameterParserUtil.parseStringParamAndDecodeAndSanitize(request.getParameter("type"), null, charset); - String extraParam = ParameterParserUtil.parseStringParamAndDecodeAndSanitize(request.getParameter("extraParam"), null, charset); + String extraParam = ParameterParserUtil.parseStringParamAndDecode(request.getParameter("extraParam"), null, charset); boolean isAcceptCerts = ParameterParserUtil.parseBooleanParam(request.getParameter("isAcceptInsecureCerts"), true); List capabilities; diff --git a/source/src/main/java/org/cerberus/core/servlet/manualtestcase/CreateUpdateTestCaseExecutionFile.java b/source/src/main/java/org/cerberus/core/servlet/manualtestcase/CreateUpdateTestCaseExecutionFile.java index 5fb6aab596..95cd1dcb11 100644 --- a/source/src/main/java/org/cerberus/core/servlet/manualtestcase/CreateUpdateTestCaseExecutionFile.java +++ b/source/src/main/java/org/cerberus/core/servlet/manualtestcase/CreateUpdateTestCaseExecutionFile.java @@ -129,15 +129,15 @@ protected void processRequest(HttpServletRequest request, HttpServletResponse re ApplicationContext appContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext()); IRecorderService recorderService = appContext.getBean(IRecorderService.class); - TestCaseStepActionExecution testCaseStepActionExecution = null; - TestCaseStepActionControlExecution testCaseStepActionControlExecution = null; + TestCaseStepActionExecution executionAction = null; + TestCaseStepActionControlExecution executionControl = null; JSONArray obj = null; if (action) { obj = new JSONArray(fileData.get("action")); - testCaseStepActionExecution = updateTestCaseStepActionExecutionFromJsonArray(obj, appContext); + executionAction = updateTestCaseStepActionExecutionFromJsonArray(obj, appContext); } else { obj = new JSONArray(fileData.get("control")); - testCaseStepActionControlExecution = updateTestCaseStepActionControlExecutionFromJsonArray(obj, appContext); + executionControl = updateTestCaseStepActionControlExecutionFromJsonArray(obj, appContext); } if (description.isEmpty()) { @@ -147,7 +147,7 @@ protected void processRequest(HttpServletRequest request, HttpServletResponse re .replace("%REASON%", "desc is missing!")); ans.setResultMessage(msg); } else { - ans = recorderService.recordManuallyFile(testCaseStepActionExecution, testCaseStepActionControlExecution, extension, description, file, idex, fileName, fileID); + ans = recorderService.recordManuallyFile(executionAction, executionControl, extension, description, file, idex, fileName, fileID); } if (ans.isCodeEquals(MessageEventEnum.DATA_OPERATION_OK.getCode())) { diff --git a/source/src/main/java/org/cerberus/core/servlet/zzpublic/RunTestCaseV002.java b/source/src/main/java/org/cerberus/core/servlet/zzpublic/RunTestCaseV002.java index cf4d1a4392..491441bc13 100644 --- a/source/src/main/java/org/cerberus/core/servlet/zzpublic/RunTestCaseV002.java +++ b/source/src/main/java/org/cerberus/core/servlet/zzpublic/RunTestCaseV002.java @@ -74,7 +74,7 @@ public class RunTestCaseV002 extends HttpServlet { private static final org.apache.logging.log4j.Logger LOG = org.apache.logging.log4j.LogManager.getLogger(RunTestCaseV002.class); - public static final String SERVLET_URL = "/RunTestCaseV002"; + public static final String SERVLET_URL = "RunTestCaseV002"; public static final String PARAMETER_TEST = "Test"; public static final String PARAMETER_TEST_CASE = "TestCase"; diff --git a/source/src/main/java/org/cerberus/core/util/DateUtil.java b/source/src/main/java/org/cerberus/core/util/DateUtil.java index b5158378c0..67b291fbd2 100644 --- a/source/src/main/java/org/cerberus/core/util/DateUtil.java +++ b/source/src/main/java/org/cerberus/core/util/DateUtil.java @@ -40,6 +40,13 @@ public class DateUtil { */ public static final String DATE_FORMAT_TIMESTAMP = "yyyyMMddHHmmssSSS"; + /** + * SimpleDateFormat use to display inside reports + */ + public static final String DATE_FORMAT_REPORT = "MM/dd/yyyy HH:mm:ss"; + public static final String DATE_FORMAT_REPORT_TIME = "HH:mm:ss"; + public static final String DATE_FORMAT_REPORT_FILE = "yyMMddHHmmss"; + private DateUtil() { } diff --git a/source/src/main/java/org/cerberus/core/util/StringUtil.java b/source/src/main/java/org/cerberus/core/util/StringUtil.java index d72044ba4d..453cf9c0bd 100644 --- a/source/src/main/java/org/cerberus/core/util/StringUtil.java +++ b/source/src/main/java/org/cerberus/core/util/StringUtil.java @@ -313,7 +313,7 @@ public static String encodeAsJavaScriptURIComponent(String stringToEncode) { */ public static String cleanHostURL(String host) { String newHost = host; - if (!(host.startsWith(HTTP_PREFIX) || host.startsWith(HTTPS_PREFIX) || host.startsWith(FTP_PREFIX) || host.startsWith(FTPS_PREFIX))) { + if (!(host.startsWith(HTTP_PREFIX) || host.startsWith(HTTPS_PREFIX) || host.startsWith(FTP_PREFIX) || host.startsWith(FTPS_PREFIX) || host.startsWith(FILE_PREFIX))) { // No prefix so we put http:// by default. newHost = HTTP_PREFIX + host; } @@ -330,7 +330,7 @@ public static String cleanHostURL(String host) { * @return formatted host */ public static String removeProtocolFromHostURL(String host) { - String newHost = host.replace(HTTP_PREFIX, "").replace(HTTPS_PREFIX, "").replace(FTP_PREFIX, "").replace(FTPS_PREFIX, ""); + String newHost = host.replace(HTTP_PREFIX, "").replace(HTTPS_PREFIX, "").replace(FTP_PREFIX, "").replace(FTPS_PREFIX, "").replace(FILE_PREFIX, ""); LOG.debug("Removed protocol host from {} to {}", host, newHost); return newHost; diff --git a/source/src/main/resources/database.sql b/source/src/main/resources/database.sql index 74fc6f0cf5..a0065f83b3 100644 --- a/source/src/main/resources/database.sql +++ b/source/src/main/resources/database.sql @@ -6181,3 +6181,51 @@ INSERT INTO `parameter` (`system`, `param`, `value`, `description`) -- 1742 ALTER TABLE `appservice` ADD COLUMN `AvroSchema` MEDIUMTEXT NULL DEFAULT NULL AFTER `SchemaRegistryUrl`; + +-- 1743-1745 +ALTER TABLE `appservice` + ADD COLUMN `AvroSchemaKey` MEDIUMTEXT NULL DEFAULT NULL AFTER `SchemaRegistryUrl`; +ALTER TABLE `appservice` + CHANGE COLUMN `AvroSchema` `AvroSchemaValue` MEDIUMTEXT NULL DEFAULT NULL ; +ALTER TABLE `appservice` + ADD COLUMN `IsAvroEnableKey` BOOLEAN DEFAULT 0 AFTER `SchemaRegistryUrl`, + ADD COLUMN `IsAvroEnableValue` BOOLEAN DEFAULT 0 AFTER `AvroSchemaKey`; + +-- 1746 +INSERT INTO `parameter` (`system`, `param`, `value`, `description`) + VALUES ('', 'cerberus_xray_tokencache_duration', '300', 'Cache duration in second of JIRA XRay token (default to 300 seconds / 5 minutes).'), + ('', 'cerberus_xray_sendenvironments_enable', 'false', 'boolean in order to activate or not the sending of environments to XRay.'); + +-- 1747 +ALTER TABLE `tag` + ADD COLUMN `XRayMessage` TEXT NULL AFTER `XRayURL`; + +-- 1748 +INSERT INTO `invariant` (`idname`, `value`, `sort`, `description`, `VeryShortDesc`, `gp1`, `gp2`, `gp3`) VALUES + ('SRVTYPE', 'MONGODB', '100', 'MongoDB Service', '', '', '', ''); + +-- 1749 +INSERT INTO `invariant` (`idname`, `value`, `sort`, `description`) + VALUES ('SRVMETHOD', 'FIND', 800 , 'Find a MongoDB Record'); + +-- 1750 +INSERT INTO `invariant` (`idname`, `value`, `sort`, `description`, `VeryShortDesc`) + VALUES ('CONTROL', 'verifyElementChecked', 4930, 'Verify the element (checkbox) is checked','verifyElementChecked'), + ('CONTROL', 'verifyElementNotChecked', 4940, 'Verify the element (checkbox) is not checked','verifyElementNotChecked'); + +-- 1751 +INSERT INTO `invariant` (`idname`, `value`, `sort`, `description`, `veryshortdesc`) + VALUES ('LANGUAGE', 'fa', 400, 'فارسی', 'فارسی'); + +-- 1752 +INSERT INTO `parameter` (`system`, `param`, `value`, `description`) + VALUES ('', 'cerberus_instancelogo_url', 'https://vm.cerberus-testing.org/img/logo.png', 'URl that point to the instance logo. Use that parameter in order to personalize some screens and pdf report.'), + ('', 'cerberus_pdfcampaignreportdisplaycountry_boolean', 'true', 'Boolean in order to show or hide the country column on pdf campaign execution pdf report.'); + +-- 1753 +INSERT INTO `invariant` (`idname`, `value`, `sort`, `description`, `veryshortdesc`) + VALUES ('ACTION', 'switchToContext', 5450, 'Switch to another application context', 'switchToContext'); + +-- 1754 +ALTER TABLE tag MODIFY COLUMN Description TEXT NULL; + diff --git a/source/src/main/resources/documentation/D1/include/en/testmanagement_tcactions_en.adoc b/source/src/main/resources/documentation/D1/include/en/testmanagement_tcactions_en.adoc index 0b2650a027..85be522968 100644 --- a/source/src/main/resources/documentation/D1/include/en/testmanagement_tcactions_en.adoc +++ b/source/src/main/resources/documentation/D1/include/en/testmanagement_tcactions_en.adoc @@ -139,6 +139,18 @@ title=titleOfThisNewWindow url=http://url_of_this_new_window ==== +==== switchToContext +|=== + +| *[red]#GUI#* | *[red]#SRV#* | *[green]#APK#* | *[green]#IPA#* | *[red]#FAT#* | *[red]#BAT#* + +|=== +Switch the current application context to another. + +*[blue]#Value1#* Name of the context you want to switch to. If the value is empty, this will switch to the default context "NATIVE_APP". + For example, you can set this action with defined value to switch on the context you want, then do your actions in this context, and finally set again + this action with no value to get back to the default context. + ==== manageDialog |=== diff --git a/source/src/main/resources/documentation/D1/include/en/testmanagement_tccontrols_en.adoc b/source/src/main/resources/documentation/D1/include/en/testmanagement_tccontrols_en.adoc index 390fc3396c..ddafd57aa2 100644 --- a/source/src/main/resources/documentation/D1/include/en/testmanagement_tccontrols_en.adoc +++ b/source/src/main/resources/documentation/D1/include/en/testmanagement_tccontrols_en.adoc @@ -6,6 +6,8 @@ | getPageSource | Force the page source to be retrieved and stored to be checked for detailed analysis. | | takeScreenshot | Force to take a screenshot. Image can be automatically crop when taking the screenshot allowing to automatize clean application or web site screenshot (without Operating system header or footer elements). | | verifyElementClickable | *[green]#OK#* if *[red]#Element#* is clickable. | +| verifyElementChecked | *[green]#OK#* if *[red]#Checkbox#* is checked. | +| verifyElementNotChecked | *[green]#OK#* if *[red]#Checkbox#* is not checked. | | verifyElementDifferent | TBD | | verifyElementEquals | TBD | | verifyElementinElement | *[green]#OK#* if *[red]#Sub Element#* is inside *[red]#Master Element#*. That can be used to check if an option is available inside a select box. | diff --git a/source/src/main/resources/documentation/D1/include/en/testmanagement_tcproperties_en.adoc b/source/src/main/resources/documentation/D1/include/en/testmanagement_tcproperties_en.adoc index 4946af1930..665c8d86dd 100644 --- a/source/src/main/resources/documentation/D1/include/en/testmanagement_tcproperties_en.adoc +++ b/source/src/main/resources/documentation/D1/include/en/testmanagement_tcproperties_en.adoc @@ -206,10 +206,13 @@ If SubData is not defined, the key value subdata will be used. | %system.EXESTORAGEURL% | Path where media are stored (based from the exeid). | %system.EXEELAPSEDMS% | Elapsed time in ms since the beginning of the execution (can be used to perform timing controls). | %system.CURRENTSTEP_INDEX% | Index number of the current step execution. Can be used when looping over a step. +| %system.CURRENTSTEP_SORT% | Sort number of the current step execution. Can be used when looping over a step. | %system.CURRENTSTEP_STARTISO% | ISO Timestamp of the beginning of the step execution. | %system.CURRENTSTEP_ELAPSEDMS% | Elapsed time in ms since the beginning of the current step execution (can be used to perform timing controls). -| %system.STEP.n.RETURNCODE% | Return Code of the step n. n being the execution sequence of the step (sort). +| %system.STEP.n.n.RETURNCODE% | Return Code of the step n. n being the execution sequence of the step (sort). | %system.LASTSERVICE_HTTPCODE% | Http return code of the last service called. +| %system.LASTSERVICE_CALL% | Last JSON Service call. +| %system.LASTSERVICE_RESPONSE% | Last JSON Service answer. | %system.TODAY-yyyy% | Year of today | %system.TODAY-MM% | Month of today | %system.TODAY-dd% | Day of today diff --git a/source/src/main/resources/documentation/D2/documentation_en.adoc b/source/src/main/resources/documentation/D2/documentation_en.adoc index 3d5a2977a4..834b139a02 100644 --- a/source/src/main/resources/documentation/D2/documentation_en.adoc +++ b/source/src/main/resources/documentation/D2/documentation_en.adoc @@ -273,3 +273,7 @@ include::include/en/{file-to-include}[] == 4.16 :file-to-include: changelog_4.16_en.adoc include::include/en/{file-to-include}[] + +== 4.17 +:file-to-include: changelog_4.17_en.adoc +include::include/en/{file-to-include}[] diff --git a/source/src/main/resources/documentation/D2/include/en/changelog_4.16_en.adoc b/source/src/main/resources/documentation/D2/include/en/changelog_4.16_en.adoc index 81b1329dbe..cdb2da6a32 100644 --- a/source/src/main/resources/documentation/D2/include/en/changelog_4.16_en.adoc +++ b/source/src/main/resources/documentation/D2/include/en/changelog_4.16_en.adoc @@ -1,10 +1,22 @@ *Bug fixes* [square] -* none +* Kafka Service Props heritage is now working correctly #2425 +* Special characters supported on email notifications. +* Fixed redirection on empty page after saving testcase. +* Fixed issue on testcase creation from header #2416 +* Allow to use property getFromJS for GUI Application type. +* Action value3 is now decoded. #2413 *Improvements / New features* [square] -* none +* Improved autocomplete feature on testcase script page. It has been added to almost all possible fields. +* Improvements on new run modal. filter apply on key press + robot select is no longer mandatory +* Timeout overwrite feature is now also available for Appium and Service calls. #2331 +* Better responsiveness on small screens on execution page. +* Progress bar on memory consumption on maintenance page +* Kafka Avro Schema registry URL now decoded #2426 +* Added Kafka AVRO support also on key. #2418 +* XRay Integration with ERROR message when link is not done + tokencache parameter + environments synchronisation parameter. *Warning to be considered before applying the version (deprecated features)* [square] diff --git a/source/src/main/resources/documentation/D2/include/en/changelog_4.17_en.adoc b/source/src/main/resources/documentation/D2/include/en/changelog_4.17_en.adoc new file mode 100644 index 0000000000..1f246c49c9 --- /dev/null +++ b/source/src/main/resources/documentation/D2/include/en/changelog_4.17_en.adoc @@ -0,0 +1,19 @@ +*Bug fixes* +[square] +* Fixed scrollTo action. #2458 +* Fixed wrong status on manual test execution. #2455 +* Fixed impossibility to delete all property with the same name. #2454 +* Fixed the Job that CANCELLED execution queue entries so that it does not not consider the timeout from the time it was inserted to the queue but the time when the execution was triggered. #2472 +* Service Call JSON now display the proper Kafka Filter Header path and value #2465 +* Record a file at control lavel was saving it at action level #2412 + +*Improvements / New features* +[square] +* Support for MongoDB Service type. +* Added background on steps according to the status and displayed condition when step NE on TestcaseExecution page. #2463 +* A pdf report is now available for campaign execution for download #2475 +* New action "Switch To Context" #2408 + +*Warning to be considered before applying the version (deprecated features)* +[square] +* none diff --git a/source/src/main/resources/documentation/D3/include/en/howto_externaltools_xray_en.adoc b/source/src/main/resources/documentation/D3/include/en/howto_externaltools_xray_en.adoc index cc33087088..bf9bedc725 100644 --- a/source/src/main/resources/documentation/D3/include/en/howto_externaltools_xray_en.adoc +++ b/source/src/main/resources/documentation/D3/include/en/howto_externaltools_xray_en.adoc @@ -78,5 +78,15 @@ image:jiracloud5.png[FR,800,800] [NOTE] ==== In case or error you can consult the _Log viewer_ from _Administration_ menu that will report the URL called and error received from the JIRA server. +That error message also appear on Campaign execution screen as a tooltip on the ERROR field ==== +[NOTE] +==== +Token Cache duration can be tuned thanks to parameter : cerberus_xray_tokencache_duration +==== + +[NOTE] +==== +Environments can be send to JIRA XRay if you activate parameter : cerberus_xray_sendenvironments_enable +==== diff --git a/source/src/main/webapp/DatabaseMaintenance.jsp b/source/src/main/webapp/DatabaseMaintenance.jsp index 86d5f104e6..2ad2b652f0 100644 --- a/source/src/main/webapp/DatabaseMaintenance.jsp +++ b/source/src/main/webapp/DatabaseMaintenance.jsp @@ -64,7 +64,7 @@ // this is used in order to execute only 1 instruction at a time as it make take a lot of time to process. boolean SQLExecuted = false; // SQL that has version equal to SQLLimit will not be executed automatically. - Integer SQLLimit = 1743; // 4.15 Version LEVEL. + Integer SQLLimit = 1748; // 4.16 Version LEVEL. IFactoryMyversion factoryMyversion; try { diff --git a/source/src/main/webapp/Homepage.jsp b/source/src/main/webapp/Homepage.jsp index ea5ce48e11..0fc8a53ded 100644 --- a/source/src/main/webapp/Homepage.jsp +++ b/source/src/main/webapp/Homepage.jsp @@ -223,11 +223,11 @@
-
+
-
+
diff --git a/source/src/main/webapp/ReportingExecutionByTag.jsp b/source/src/main/webapp/ReportingExecutionByTag.jsp index fbd6314f9a..95dbff390b 100644 --- a/source/src/main/webapp/ReportingExecutionByTag.jsp +++ b/source/src/main/webapp/ReportingExecutionByTag.jsp @@ -271,16 +271,21 @@ aria-describedby="basic-addon1">
-
+
-
+
+
diff --git a/source/src/main/webapp/TestCaseExecution.jsp b/source/src/main/webapp/TestCaseExecution.jsp index 370b572604..b3d96f3954 100644 --- a/source/src/main/webapp/TestCaseExecution.jsp +++ b/source/src/main/webapp/TestCaseExecution.jsp @@ -19,688 +19,821 @@ along with Cerberus. If not, see . --%> -<%@page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> +<%@page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %> - - - <%@ include file="include/global/dependenciesInclusions.html" %> - Execution Detail - - - - - - - - - - + + + <%@ include file="include/global/dependenciesInclusions.html" %> + Execution Detail + + + + + + + + + + - - - <%@ include file="include/global/header.html"%> - <%@ include file="include/utils/modal-generic.html"%> - <%@ include file="include/pages/testcasescript/manageProperties.html"%> - <%@ include file="include/transversalobject/TestCaseSimpleExecution.html"%> -
- <%@ include file="include/global/messagesArea.html"%> - <%@ include file="include/transversalobject/TestCaseExecutionQueue.html"%> - <%@ include file="include/transversalobject/TestCase.html"%> - <%@ include file="include/transversalobject/File.html"%> -

Execution Detail

-
-
-
-
-
-
- -
+ + +<%@ include file="include/global/header.html" %> +<%@ include file="include/utils/modal-generic.html" %> +<%@ include file="include/pages/testcasescript/manageProperties.html" %> +<%@ include file="include/transversalobject/TestCaseSimpleExecution.html" %> +
+ <%@ include file="include/global/messagesArea.html" %> + <%@ include file="include/transversalobject/TestCaseExecutionQueue.html" %> + <%@ include file="include/transversalobject/TestCase.html" %> + <%@ include file="include/transversalobject/File.html" %> +

Execution Detail

+
+
+
+
+
+
+ +
+
+
+ + -
-
+
+
+
+
-
-
- -
-