diff --git a/build-system/pom.xml b/build-system/pom.xml index 7363221f894..d18acead028 100644 --- a/build-system/pom.xml +++ b/build-system/pom.xml @@ -1466,8 +1466,8 @@ - /opt/Bamboo_db_configs/mssqljdbc4.jar - /opt/Bamboo_db_configs/ojdbc6.jar + /opt/jenkins_db_configs/mssqljdbc4.jar + /opt/jenkins_db_configs/ojdbc7.jar c:\Program Files\Microsoft JDBC DRIVER 4.0 for SQL Server\sqljdbc_4.0\enu\sqljdbc4.jar diff --git a/config/sql/_all/sqlserver-3.8-all.sql b/config/sql/_all/sqlserver-3.8-all.sql index be207b67c2d..e3e9aef4d9b 100644 --- a/config/sql/_all/sqlserver-3.8-all.sql +++ b/config/sql/_all/sqlserver-3.8-all.sql @@ -560,7 +560,7 @@ CREATE TABLE m_focus ( validityStatus INT, costCenter NVARCHAR(255) COLLATE database_default, emailAddress NVARCHAR(255) COLLATE database_default, - hasPhoto BIT DEFAULT FALSE NOT NULL, + hasPhoto BIT DEFAULT 0 NOT NULL, locale NVARCHAR(255) COLLATE database_default, locality_norm NVARCHAR(255) COLLATE database_default, locality_orig NVARCHAR(255) COLLATE database_default, diff --git a/dist/src/main/bin/midpoint.bat b/dist/src/main/bin/midpoint.bat index fd70b6fb8fd..12be71bef7c 100644 --- a/dist/src/main/bin/midpoint.bat +++ b/dist/src/main/bin/midpoint.bat @@ -2,71 +2,68 @@ setlocal -set "BIN_DIR=%~dp0%~2" -if not "%MIDPOINT_HOME%" == "" goto gotHome -cd "%BIN_DIR%.." -mkdir var -cd var -mkdir log -cd "%BIN_DIR%.." -set "MIDPOINT_HOME=%cd%\var" -echo %MIDPOINT_HOME% -echo %BIN_DIR% -:gotHome - -rem if script for start and stop exists -if exist "%BIN_DIR%\midpoint.bat" goto okBoot -echo %BIN_DIR% -echo The midpoint.bat file is not in \bin directory or is no accessible -goto end -:okBoot - -rem if start/stop out file exists -if not "%BOOT_OUT%" == "" goto okOut -set "BOOT_OUT=%MIDPOINT_HOME%\log\midpoint.out" -echo %BOOT_OUT% -:okOut - -rem MIDPOINT_WAR if not defined -if exist "%cd%\lib\midpoint.war" goto gotWar -echo The midpoint.war is not in \lib directory -echo Can not start midPoint +if "%1" == "start" goto doStart +if "%1" == "stop" goto doStop + +echo Error: No command given. Specify either start or stop. goto end -:gotWar -if "%MIDPOINT_HOME%" == "%MIDPOINT_HOME:;=%" goto homeNoSemicolon +:doStart +set BIN_DIR=%~dp0 +set LIB_DIR=%BIN_DIR%..\lib + +if "%MIDPOINT_HOME%" == "" ( + cd "%BIN_DIR%.." + if not exist var mkdir var + if not exist var\log mkdir var\log + set "MIDPOINT_HOME=%BIN_DIR%..\var" +) echo Using MIDPOINT_HOME: "%MIDPOINT_HOME%" -echo Unable to start as MIDPOINT_HOME contains a semicolon (;) character -goto end -:homeNoSemicolon +if not exist "%BIN_DIR%midpoint.bat" ( + echo Error: The midpoint.bat file is not in bin directory or is not accessible. + goto end +) -rem ----- Execute The Requested Command --------------------------------------- +if not exist "%LIB_DIR%\midpoint.war" ( + echo Error: The midpoint.war is not in the lib directory + goto end +) -echo Using MIDPOINT_HOME: "%MIDPOINT_HOME%" +if not "%MIDPOINT_HOME%" == "%MIDPOINT_HOME:;=%" ( + echo Error: MIDPOINT_HOME contains a semicolon ";" character. + goto end +) -set _EXECJAVA=%_RUNJAVA% -set _NOHUP=nohup -set ACTION=start +if "%BOOT_OUT%" == "" set BOOT_OUT=%MIDPOINT_HOME%\log\midpoint.out +echo Using BOOT_OUT: "%BOOT_OUT%" -if ""%1"" == ""start"" goto doStart -if ""%1"" == ""stop"" goto doStop +rem ----- Execute The Requested Start Command --------------------------------------- -:doStart shift -goto execStart +set RUN_JAVA=javaw +if not "%JAVA_HOME%" == "" set RUN_JAVA=%JAVA_HOME%\bin\javaw + +echo Using RUN_JAVA: "%RUN_JAVA%" +echo Using JAVA_OPTS: "%JAVA_OPTS%" +echo Using parameters: "%*" +echo. +echo Starting midPoint. +start /b %RUN_JAVA% -jar %JAVA_OPTS% -Xms2048M -Xmx2048M -Dpython.cachedir="%MIDPOINT_HOME%\tmp" -Djavax.net.ssl.trustStore="%MIDPOINT_HOME%\keystore.jceks" -Djavax.net.ssl.trustStoreType=jceks -Dmidpoint.home="%MIDPOINT_HOME%" "%LIB_DIR%\midpoint.war" %* > "%BOOT_OUT%" 2>&1 +goto end :doStop -shift -goto execStop -:execStart -echo "%cd%\lib\midpoint.war" -start /b javaw -jar -Xms2048M -Xmx2048M -Dpython.cachedir="%MIDPOINT_HOME%\tmp" -Djavax.net.ssl.trustStore="%MIDPOINT_HOME%\keystore.jceks" -Djavax.net.ssl.trustStoreType=jceks -Dmidpoint.home="%MIDPOINT_HOME%" "%cd%\lib\midpoint.war" > "%BOOT_OUT%" 2>&1 & -goto end +set MIDPOINT_PORT=8080 -:execStop -echo "%cd%\lib\midpoint.war" -FOR /F "usebackq tokens=5" %%i IN (`netstat -aon ^| findstr "0.0.0.0:8080"`) DO taskkill /F /PID %%i +shift +echo Trying to find and stop a process listening on port %MIDPOINT_PORT%... +set MIDPOINT_FOUND= +FOR /F "usebackq tokens=5" %%i IN (`netstat -aon ^| findstr "0.0.0.0:%MIDPOINT_PORT% "`) DO ( + taskkill /F /PID %%i + set MIDPOINT_FOUND=true +) +if not "%MIDPOINT_FOUND%" == "true" echo No process listening on %MIDPOINT_PORT% was found. +goto end :end diff --git a/dist/src/main/bin/ninja.bat b/dist/src/main/bin/ninja.bat index 77c533d4bb8..16451bf82cf 100644 --- a/dist/src/main/bin/ninja.bat +++ b/dist/src/main/bin/ninja.bat @@ -2,50 +2,59 @@ setlocal -set "BIN_DIR=%~dp0" - -rem if script for execution is in bin directory -if exist "%BIN_DIR%\ninja.bat" goto okBoot -echo %BIN_DIR% -echo The keys.bat file is not in \bin -goto end -:okBoot - -rem set midpoint.home -if not "%MIDPOINT_HOME%" == "" goto gotHome -cd "%BIN_DIR%.." -if exist "%BIN_DIR%..\var" goto setHome -echo %BIN_DIR% -echo ERROR: midpoint.home directory desn't exist -goto end -:setHome - -set "MIDPOINT_HOME=%cd%\var" -echo %MIDPOINT_HOME% -echo %BIN_DIR% -:gotHome - -rem NINJA_JAR if not defined -if exist "%cd%\lib\ninja.jar" goto gotJar -echo The ninja.jar is not in \lib directory -echo Can not start ninja -goto end -:gotJar - -if "%MIDPOINT_HOME%" == "%MIDPOINT_HOME:;=%" goto homeNoSemicolon +set NINJA_JAR=ninja.jar + +set BIN_DIR=%~dp0 +set ROOT_DIR=%BIN_DIR%.. +set VAR_DIR=%ROOT_DIR%\var +set NINJA_JAR_PATH=%ROOT_DIR%\lib\%NINJA_JAR% + +set PARAMETERS=%* + +set LOADER_PATH= +:argloop +IF NOT "%1"=="" ( + IF "%1"=="-j" ( + SET LOADER_PATH="-Dloader.path=%2" + SHIFT + ) + IF "%1"=="--jdbc" ( + SET LOADER_PATH="-Dloader.path=%2" + SHIFT + ) + SHIFT + GOTO :argloop +) + +if "%MIDPOINT_HOME%" == "" ( + if not exist "%VAR_DIR%" ( + echo Error: Default midpoint.home directory "%VAR_DIR%" does not exist. + goto end + ) + set MIDPOINT_HOME=%VAR_DIR% +) + +if not "%MIDPOINT_HOME%" == "%MIDPOINT_HOME:;=%" ( + echo Error: Unable to start as MIDPOINT_HOME contains a semicolon ";" character + goto end +) + echo Using MIDPOINT_HOME: "%MIDPOINT_HOME%" -echo Unable to start as MIDPOINT_HOME contains a semicolon (;) character -goto end -:homeNoSemicolon +if not exist "%NINJA_JAR_PATH%" ( + echo Error: %NINJA_JAR% is not in the lib directory. + echo Cannot start ninja + goto end +) rem ----- Execute The Requested Command --------------------------------------- -echo Using MIDPOINT_HOME: "%MIDPOINT_HOME%" +set RUN_JAVA=java +if not "%JAVA_HOME%" == "" set RUN_JAVA=%JAVA_HOME%\bin\java -start /b java -jar "%cd%\lib\ninja.jar" -m "%MIDPOINT_HOME%" %* -goto end +echo Using LOADER_PATH: %LOADER_PATH% +echo Using RUN_JAVA: "%RUN_JAVA%" +"%RUN_JAVA%" %LOADER_PATH% -jar "%NINJA_JAR_PATH%" -m "%MIDPOINT_HOME%" %PARAMETERS% :end - diff --git a/dist/src/main/bin/ninja.sh b/dist/src/main/bin/ninja.sh index bd52ce9bdd6..f5159f6d31f 100755 --- a/dist/src/main/bin/ninja.sh +++ b/dist/src/main/bin/ninja.sh @@ -46,9 +46,9 @@ fi [ -z "$MIDPOINT_HOME" ] && MIDPOINT_HOME=`cd "$SCRIPT_PATH../var" >/dev/null; pwd` -cd "$SCRIPT_PATH../lib" +#cd "$SCRIPT_PATH../lib" -if [ ! -f ninja.jar ] ; then +if [ ! -f lib/ninja.jar ] ; then echo "ERROR: ninja.jar is not in /lib directory" exit 1 fi @@ -65,7 +65,18 @@ else _RUNJAVA="$JAVA_HOME"/bin/java fi +while getopts ":j:" opt; do + case $opt in + j) + JDBC_DRIVER=$OPTARG + ;; + esac +done + +if [ ! -z "$JDBC_DRIVER" ] ; then + JDBC_DRIVER="-Dloader.path=$JDBC_DRIVER" +fi -exec "$_RUNJAVA" -jar $SCRIPT_PATH../lib/ninja.jar -m $MIDPOINT_HOME $@ +exec "$_RUNJAVA" $JDBC_DRIVER -jar $SCRIPT_PATH../lib/ninja.jar -m $MIDPOINT_HOME $@ diff --git a/dist/src/main/bin/ninja37.bat b/dist/src/main/bin/ninja37.bat index e57d7746ee0..c1cf554ba09 100644 --- a/dist/src/main/bin/ninja37.bat +++ b/dist/src/main/bin/ninja37.bat @@ -2,50 +2,59 @@ setlocal -set "BIN_DIR=%~dp0" - -rem if script for execution is in bin directory -if exist "%BIN_DIR%\ninja37.bat" goto okBoot -echo %BIN_DIR% -echo The keys.bat file is not in \bin -goto end -:okBoot - -rem set midpoint.home -if not "%MIDPOINT_HOME%" == "" goto gotHome -cd "%BIN_DIR%.." -if exist "%BIN_DIR%..\var" goto setHome -echo %BIN_DIR% -echo ERROR: midpoint.home directory desn't exist -goto end -:setHome - -set "MIDPOINT_HOME=%cd%\var" -echo %MIDPOINT_HOME% -echo %BIN_DIR% -:gotHome - -rem NINJA_JAR if not defined -if exist "%cd%\lib\ninja-3.7.2-SNAPSHOT.jar" goto gotJar -echo The ninja-3.7.2-SNAPSHOT.jar is not in \lib directory -echo Can not start ninja -goto end -:gotJar - -if "%MIDPOINT_HOME%" == "%MIDPOINT_HOME:;=%" goto homeNoSemicolon +set NINJA_JAR=ninja-3.7.2-SNAPSHOT.jar + +set BIN_DIR=%~dp0 +set ROOT_DIR=%BIN_DIR%.. +set VAR_DIR=%ROOT_DIR%\var +set NINJA_JAR_PATH=%ROOT_DIR%\lib\%NINJA_JAR% + +set PARAMETERS=%* + +set LOADER_PATH= +:argloop +IF NOT "%1"=="" ( + IF "%1"=="-j" ( + SET LOADER_PATH="-Dloader.path=%2" + SHIFT + ) + IF "%1"=="--jdbc" ( + SET LOADER_PATH="-Dloader.path=%2" + SHIFT + ) + SHIFT + GOTO :argloop +) + +if "%MIDPOINT_HOME%" == "" ( + if not exist "%VAR_DIR%" ( + echo Error: Default midpoint.home directory "%VAR_DIR%" does not exist. + goto end + ) + set MIDPOINT_HOME=%VAR_DIR% +) + +if not "%MIDPOINT_HOME%" == "%MIDPOINT_HOME:;=%" ( + echo Error: Unable to start as MIDPOINT_HOME contains a semicolon ";" character + goto end +) + echo Using MIDPOINT_HOME: "%MIDPOINT_HOME%" -echo Unable to start as MIDPOINT_HOME contains a semicolon (;) character -goto end -:homeNoSemicolon +if not exist "%NINJA_JAR_PATH%" ( + echo Error: %NINJA_JAR% is not in the lib directory. + echo Cannot start ninja + goto end +) rem ----- Execute The Requested Command --------------------------------------- -echo Using MIDPOINT_HOME: "%MIDPOINT_HOME%" +set RUN_JAVA=java +if not "%JAVA_HOME%" == "" set RUN_JAVA=%JAVA_HOME%\bin\java -start /b java -jar "%cd%\lib\ninja-3.7.2-SNAPSHOT.jar" -m "%MIDPOINT_HOME%" %* -goto end +echo Using LOADER_PATH: %LOADER_PATH% +echo Using RUN_JAVA: "%RUN_JAVA%" +"%RUN_JAVA%" %LOADER_PATH% -jar "%NINJA_JAR_PATH%" -m "%MIDPOINT_HOME%" %PARAMETERS% :end - diff --git a/dist/src/main/bin/ninja37.sh b/dist/src/main/bin/ninja37.sh index 6377e0169e9..f5159f6d31f 100755 --- a/dist/src/main/bin/ninja37.sh +++ b/dist/src/main/bin/ninja37.sh @@ -46,10 +46,10 @@ fi [ -z "$MIDPOINT_HOME" ] && MIDPOINT_HOME=`cd "$SCRIPT_PATH../var" >/dev/null; pwd` -cd "$SCRIPT_PATH../lib" +#cd "$SCRIPT_PATH../lib" -if [ ! -f ninja-3.7.2-SNAPSHOT.jar ] ; then - echo "ERROR: ninja-3.7.2-SNAPSHOT.jar is not in /lib directory" +if [ ! -f lib/ninja.jar ] ; then + echo "ERROR: ninja.jar is not in /lib directory" exit 1 fi @@ -65,7 +65,18 @@ else _RUNJAVA="$JAVA_HOME"/bin/java fi +while getopts ":j:" opt; do + case $opt in + j) + JDBC_DRIVER=$OPTARG + ;; + esac +done + +if [ ! -z "$JDBC_DRIVER" ] ; then + JDBC_DRIVER="-Dloader.path=$JDBC_DRIVER" +fi -exec "$_RUNJAVA" -jar $SCRIPT_PATH../lib/ninja-3.7.2-SNAPSHOT.jar -m $MIDPOINT_HOME $@ +exec "$_RUNJAVA" $JDBC_DRIVER -jar $SCRIPT_PATH../lib/ninja.jar -m $MIDPOINT_HOME $@ diff --git a/dist/src/main/bin/start.bat b/dist/src/main/bin/start.bat index 9d112c9567b..52fb4cfd62a 100644 --- a/dist/src/main/bin/start.bat +++ b/dist/src/main/bin/start.bat @@ -2,42 +2,15 @@ setlocal -set "BIN_DIR=%~dp0%~1" -if not "%MIDPOINT_HOME%" == "" goto gotHome -cd "%BIN_DIR%.." -mkdir var -cd var -mkdir log -cd "%BIN_DIR%.." -set "MIDPOINT_HOME=%cd%\var" -echo %MIDPOINT_HOME% -:gotHome +set "BIN_DIR=%~dp0" +set "EXECUTABLE=%BIN_DIR%midpoint.bat" -if exist "%BIN_DIR%\midpoint.bat" goto okHome -echo The MIDPOINT_HOME environment variable is not defined correctly -echo This environment variable is needed to run this program -goto end -:okHome +if not exist "%EXECUTABLE%" ( + echo Error: Cannot find "%EXECUTABLE%" + echo This file is needed to run this program + goto end +) -set "EXECUTABLE=%BIN_DIR%\midpoint.bat" - -rem Check that target executable exists -if exist "%EXECUTABLE%" goto okExec -echo Cannot find "%EXECUTABLE%" -echo This file is needed to run this program -goto end -:okExec - -rem Get remaining unshifted command line arguments and save them in the -set CMD_LINE_ARGS= -:setArgs -if ""%1""=="""" goto doneSetArgs -set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1 -shift -goto setArgs -:doneSetArgs - -call "%EXECUTABLE%" start %CMD_LINE_ARGS% +call "%EXECUTABLE%" start %* :end - diff --git a/dist/src/main/bin/stop.bat b/dist/src/main/bin/stop.bat index 8c3eef8e755..a742e3dda44 100644 --- a/dist/src/main/bin/stop.bat +++ b/dist/src/main/bin/stop.bat @@ -2,42 +2,15 @@ setlocal -set "BIN_DIR=%~dp0%~1" -if not "%MIDPOINT_HOME%" == "" goto gotHome -cd "%BIN_DIR%.." -mkdir var -cd var -mkdir log -cd "%BIN_DIR%.." -set "MIDPOINT_HOME=%cd%\var" -echo %MIDPOINT_HOME% -:gotHome +set "BIN_DIR=%~dp0" +set "EXECUTABLE=%BIN_DIR%midpoint.bat" -if exist "%BIN_DIR%\midpoint.bat" goto okHome -echo The MIDPOINT_HOME environment variable is not defined correctly -echo This environment variable is needed to run this program -goto end -:okHome +if not exist "%EXECUTABLE%" ( + echo Error: Cannot find "%EXECUTABLE%" + echo This file is needed to run this program + goto end +) -set "EXECUTABLE=%BIN_DIR%\midpoint.bat" - -rem Check that target executable exists -if exist "%EXECUTABLE%" goto okExec -echo Cannot find "%EXECUTABLE%" -echo This file is needed to run this program -goto end -:okExec - -rem Get remaining unshifted command line arguments and save them in the -set CMD_LINE_ARGS= -:setArgs -if ""%1""=="""" goto doneSetArgs -set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1 -shift -goto setArgs -:doneSetArgs - -call "%EXECUTABLE%" stop %CMD_LINE_ARGS% - -:end +call "%EXECUTABLE%" stop %* +:end \ No newline at end of file diff --git a/dist/src/main/bin/upgrade.bat b/dist/src/main/bin/upgrade.bat new file mode 100644 index 00000000000..6cc205fc885 --- /dev/null +++ b/dist/src/main/bin/upgrade.bat @@ -0,0 +1,69 @@ +@echo off + +rem This script upgrades specified target 3.7.x midPoint directory to midPoint 3.8 +rem by replacing appropriate files + +setlocal + +set BIN_DIR=%~dp0 +set DIST_DIR=%BIN_DIR%.. + +echo MidPoint 3.8 distribution (i.e. source) is in %DIST_DIR% + +if not exist "%DIST_DIR%\bin" goto :wrongDistribution +if not exist "%DIST_DIR%\lib" goto :wrongDistribution + +set MIDPOINT_EXISTING_FOLDER=%1 + +if x%MIDPOINT_EXISTING_FOLDER% == x goto noParameter + +echo Existing midPoint installation (i.e. target) is in %MIDPOINT_EXISTING_FOLDER% + +if not exist %MIDPOINT_EXISTING_FOLDER% goto :noExistingFolder +if not exist %MIDPOINT_EXISTING_FOLDER%\bin goto :wrongExistingFolder +if not exist %MIDPOINT_EXISTING_FOLDER%\lib goto :wrongExistingFolder +if exist %MIDPOINT_EXISTING_FOLDER%\bin.backup goto :backupAlreadyExists +if exist %MIDPOINT_EXISTING_FOLDER%\lib.backup goto :backupAlreadyExists + +echo Renaming %MIDPOINT_EXISTING_FOLDER%\bin to %MIDPOINT_EXISTING_FOLDER%\bin.backup ... +rename %MIDPOINT_EXISTING_FOLDER%\bin bin.backup + +echo Renaming %MIDPOINT_EXISTING_FOLDER%\lib to %MIDPOINT_EXISTING_FOLDER%\lib.backup ... +rename %MIDPOINT_EXISTING_FOLDER%\lib lib.backup + +echo Deleting %MIDPOINT_EXISTING_FOLDER%\doc +del /F /S /Q %MIDPOINT_EXISTING_FOLDER%\doc\* 1>nul + +echo Copying from %DIST_DIR% into %MIDPOINT_EXISTING_FOLDER% +xcopy /S /E /Y /Q "%DIST_DIR%\*" %MIDPOINT_EXISTING_FOLDER% + +echo MidPoint installation upgrade finished. + +goto :end + +:noParameter +echo --- +echo No arguments supplied. Please specify the location of existing midPoint installation that is to be updated. +goto end + +:wrongDistribution +echo --- +echo Error: Wrong distribution: Directory %DIST_DIR%\bin or %DIST_DIR%\lib does not exist. +goto end + +:noExistingFolder +echo --- +echo Error: Target folder %MIDPOINT_EXISTING_FOLDER% does not exist. +goto end + +:wrongExistingFolder +echo --- +echo Error: Wrong target folder with existing midPoint installation: Directory %MIDPOINT_EXISTING_FOLDER%\bin or %MIDPOINT_EXISTING_FOLDER%\lib does not exist. +goto end + +:backupAlreadyExists +echo --- +echo Error: Backup directory (bin.backup or lib.backup) already exists in %MIDPOINT_EXISTING_FOLDER%. This means that the upgrade has been already run. If you are sure that you want to run this upgrade, please remove the backup directories and start over. +goto end + +:end diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/result/OperationResult.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/result/OperationResult.java index 7d3c96029b0..7338cfd7b00 100644 --- a/infra/schema/src/main/java/com/evolveum/midpoint/schema/result/OperationResult.java +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/result/OperationResult.java @@ -554,6 +554,10 @@ public void computeStatus() { boolean allNotApplicable = true; String newMessage = null; for (OperationResult sub : getSubresults()) { + if (sub == null) { + continue; + } + if (sub.getStatus() != OperationResultStatus.NOT_APPLICABLE) { allNotApplicable = false; } diff --git a/model/certification-impl/src/main/java/com/evolveum/midpoint/certification/impl/AccCertCaseOperationsHelper.java b/model/certification-impl/src/main/java/com/evolveum/midpoint/certification/impl/AccCertCaseOperationsHelper.java index 6316d4b0610..66629daa037 100644 --- a/model/certification-impl/src/main/java/com/evolveum/midpoint/certification/impl/AccCertCaseOperationsHelper.java +++ b/model/certification-impl/src/main/java/com/evolveum/midpoint/certification/impl/AccCertCaseOperationsHelper.java @@ -128,11 +128,10 @@ void recordDecision(String campaignOid, long caseId, long workItemId, updateHelper.modifyObjectViaModel(AccessCertificationCampaignType.class, campaignOid, deltaList, task, result); } - List> getDeltasToCreateCases( - final AccessCertificationCampaignType campaign, AccessCertificationStageType stage, - final CertificationHandler handler, final Task task, final OperationResult result) throws SchemaException, ObjectNotFoundException { - - final List> rv = new ArrayList<>(); + void getDeltasToCreateCases( + final AccessCertificationCampaignType campaign, AccessCertificationStageType stage, + final CertificationHandler handler, ModificationsToExecute modifications, + final Task task, final OperationResult result) throws SchemaException, ObjectNotFoundException { final String campaignShortName = toShortString(campaign); @@ -197,9 +196,9 @@ List> getDeltasToCreateCases( AccessCertificationReviewerSpecificationType reviewerSpec = reviewersHelper.findReviewersSpecification(campaign, 1, task, result); - ContainerDelta caseDelta = ContainerDelta.createDelta(F_CASE, - AccessCertificationCampaignType.class, prismContext); for (AccessCertificationCaseType _case : caseList) { + ContainerDelta caseDelta = ContainerDelta.createDelta(F_CASE, + AccessCertificationCampaignType.class, prismContext); _case.setStageNumber(1); _case.setCurrentStageCreateTimestamp(stage.getStartTimestamp()); _case.setCurrentStageDeadline(stage.getDeadline()); @@ -215,11 +214,11 @@ List> getDeltasToCreateCases( PrismContainerValue caseCVal = _case.asPrismContainerValue(); caseDelta.addValueToAdd(caseCVal); LOGGER.trace("Adding certification case:\n{}", caseCVal.debugDumpLazily()); + modifications.add(caseDelta); } - rv.add(caseDelta); - LOGGER.trace("Created {} deltas to create {} cases for campaign {}", rv.size(), caseList.size(), campaignShortName); - return rv; + LOGGER.trace("Created {} deltas (in {} batches) to create {} cases for campaign {}", modifications.getTotalDeltasCount(), + modifications.batches.size(), caseList.size(), campaignShortName); } private List createWorkItems(List forReviewers, int forStage) { @@ -234,12 +233,12 @@ private List createWorkItems(List> getDeltasToAdvanceCases(AccessCertificationCampaignType campaign, AccessCertificationStageType stage, Task task, OperationResult result) - throws SchemaException, ObjectAlreadyExistsException, ObjectNotFoundException { + void getDeltasToAdvanceCases(AccessCertificationCampaignType campaign, AccessCertificationStageType stage, + ModificationsToExecute modifications, Task task, OperationResult result) + throws SchemaException, ObjectNotFoundException { LOGGER.trace("Advancing reviewers and timestamps for cases in {}", toShortString(campaign)); List caseList = queryHelper.searchCases(campaign.getOid(), null, null, result); - List> rv = new ArrayList<>(caseList.size()); int stageToBe = campaign.getStageNumber() + 1; @@ -259,7 +258,7 @@ List> getDeltasToAdvanceCases(AccessCertificationCampaignType cam _case.getWorkItem().addAll(CloneUtil.cloneCollectionMembers(workItems)); AccessCertificationResponseType currentOutcome = computationHelper.computeOutcomeForStage(_case, campaign, stageToBe); AccessCertificationResponseType overallOutcome = computationHelper.computeOverallOutcome(_case, campaign, currentOutcome); - rv.addAll(DeltaBuilder.deltaFor(AccessCertificationCampaignType.class, prismContext) + modifications.add(DeltaBuilder.deltaFor(AccessCertificationCampaignType.class, prismContext) .item(F_CASE, caseId, F_WORK_ITEM).add(PrismContainerValue.toPcvList(workItems)) .item(F_CASE, caseId, F_CURRENT_STAGE_CREATE_TIMESTAMP).replace(stage.getStartTimestamp()) .item(F_CASE, caseId, F_CURRENT_STAGE_DEADLINE).replace(stage.getDeadline()) @@ -269,14 +268,13 @@ List> getDeltasToAdvanceCases(AccessCertificationCampaignType cam .asItemDeltas()); } - LOGGER.debug("Created {} deltas to advance {} cases for campaign {}", rv.size(), caseList.size(), toShortString(campaign)); - return rv; + LOGGER.debug("Created {} deltas (in {} batches) to advance {} cases for campaign {}", modifications.getTotalDeltasCount(), + modifications.batches.size(), caseList.size(), toShortString(campaign)); } // computes outcomes at stage close (stage-level and overall) and creates appropriate deltas - List> createOutcomeDeltas(AccessCertificationCampaignType campaign, OperationResult result) throws ObjectNotFoundException, SchemaException { - List> rv = new ArrayList<>(); - + void createOutcomeDeltas(AccessCertificationCampaignType campaign, ModificationsToExecute modifications, + OperationResult result) throws SchemaException { if (LOGGER.isTraceEnabled()) { LOGGER.trace("Updating current outcome for cases in {}", toShortString(campaign)); } @@ -286,13 +284,14 @@ List> createOutcomeDeltas(AccessCertificationCampaignType campaig if (_case.getStageNumber() != campaign.getStageNumber()) { continue; } + List> deltas = new ArrayList<>(); String newStageOutcome = OutcomeUtils.toUri(computationHelper.computeOutcomeForStage(_case, campaign, campaign.getStageNumber())); if (!Objects.equals(newStageOutcome, _case.getCurrentStageOutcome())) { - rv.add(DeltaBuilder.deltaFor(AccessCertificationCampaignType.class, prismContext) + deltas.add(DeltaBuilder.deltaFor(AccessCertificationCampaignType.class, prismContext) .item(F_CASE, _case.asPrismContainerValue().getId(), F_CURRENT_STAGE_OUTCOME).replace(newStageOutcome) .asItemDelta()); } - rv.add(DeltaBuilder.deltaFor(AccessCertificationCampaignType.class, prismContext) + deltas.add(DeltaBuilder.deltaFor(AccessCertificationCampaignType.class, prismContext) .item(F_CASE, _case.asPrismContainerValue().getId(), F_EVENT).add(new StageCompletionEventType() .timestamp(clock.currentTimeXMLGregorianCalendar()) .stageNumber(campaign.getStageNumber()) @@ -301,12 +300,12 @@ List> createOutcomeDeltas(AccessCertificationCampaignType campaig String newOverallOutcome = OutcomeUtils.toUri(computationHelper.computeOverallOutcome(_case, campaign, newStageOutcome)); if (!Objects.equals(newOverallOutcome, _case.getOutcome())) { - rv.add(DeltaBuilder.deltaFor(AccessCertificationCampaignType.class, prismContext) + deltas.add(DeltaBuilder.deltaFor(AccessCertificationCampaignType.class, prismContext) .item(F_CASE, _case.asPrismContainerValue().getId(), F_OUTCOME).replace(newOverallOutcome) .asItemDelta()); } + modifications.add(deltas); } - return rv; } // TODO temporary implementation - should be done somehow in batches in order to improve performance diff --git a/model/certification-impl/src/main/java/com/evolveum/midpoint/certification/impl/AccCertUpdateHelper.java b/model/certification-impl/src/main/java/com/evolveum/midpoint/certification/impl/AccCertUpdateHelper.java index 38941e18154..155008354dd 100644 --- a/model/certification-impl/src/main/java/com/evolveum/midpoint/certification/impl/AccCertUpdateHelper.java +++ b/model/certification-impl/src/main/java/com/evolveum/midpoint/certification/impl/AccCertUpdateHelper.java @@ -112,7 +112,7 @@ public class AccCertUpdateHelper { AccessCertificationCampaignType createCampaignObject(AccessCertificationDefinitionType definition, Task task, OperationResult result) - throws SchemaException, ObjectNotFoundException, SecurityViolationException { + throws SchemaException, SecurityViolationException { AccessCertificationCampaignType newCampaign = new AccessCertificationCampaignType(prismContext); if (definition.getName() != null) { @@ -169,7 +169,7 @@ AccessCertificationCampaignType createAdHocCampaignObject return campaign; } - private PolyStringType generateCampaignName(AccessCertificationDefinitionType definition, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException { + private PolyStringType generateCampaignName(AccessCertificationDefinitionType definition, Task task, OperationResult result) throws SchemaException { String prefix = definition.getName().getOrig(); Integer lastCampaignIdUsed = definition.getLastCampaignIdUsed() != null ? definition.getLastCampaignIdUsed() : 0; for (int i = lastCampaignIdUsed+1;; i++) { @@ -207,8 +207,9 @@ public void recordLastCampaignIdUsed(String definitionOid, int lastIdUsed, Task //region ================================ Stage open ================================ - public List> getDeltasForStageOpen(AccessCertificationCampaignType campaign, AccessCertificationStageType stage, CertificationHandler handler, final Task task, OperationResult result) - throws SchemaException, ObjectNotFoundException, ObjectAlreadyExistsException { + public ModificationsToExecute getDeltasForStageOpen(AccessCertificationCampaignType campaign, AccessCertificationStageType stage, + CertificationHandler handler, final Task task, OperationResult result) + throws SchemaException, ObjectNotFoundException { Validate.notNull(campaign, "certificationCampaign"); Validate.notNull(campaign.getOid(), "certificationCampaign.oid"); @@ -220,26 +221,30 @@ public List> getDeltasForStageOpen(AccessCertificationCampaignTyp ObjectTypeUtil.toShortString(campaign), stageNumber); } - List> rv = new ArrayList<>(); + ModificationsToExecute rv = new ModificationsToExecute(); if (stageNumber == 0) { - rv.addAll(caseHelper.getDeltasToCreateCases(campaign, stage, handler, task, result)); + caseHelper.getDeltasToCreateCases(campaign, stage, handler, rv, task, result); } else { - rv.addAll(caseHelper.getDeltasToAdvanceCases(campaign, stage, task, result)); + caseHelper.getDeltasToAdvanceCases(campaign, stage, rv, task, result); } - + rv.createNewBatch(); rv.add(createStageAddDelta(stage)); - rv.addAll(createDeltasToRecordStageOpen(campaign, stage)); - rv.addAll(createTriggersForTimedActions(campaign.getOid(), 0, + rv.add(createDeltasToRecordStageOpen(campaign, stage)); + rv.add(createTriggersForTimedActions(campaign.getOid(), 0, XmlTypeConverter.toDate(stage.getStartTimestamp()), XmlTypeConverter.toDate(stage.getDeadline()), CertCampaignTypeUtil.findStageDefinition(campaign, newStageNumber).getTimedActions())); - LOGGER.trace("getDeltasForStageOpen finishing, returning {} deltas:\n{}", rv.size(), DebugUtil.debugDumpLazily(rv)); + if (LOGGER.isTraceEnabled()) { + List> allDeltas = rv.getAllDeltas(); + LOGGER.trace("getDeltasForStageOpen finishing, returning {} deltas (in {} batches):\n{}", + allDeltas.size(), rv.batches.size(), DebugUtil.debugDump(allDeltas)); + } return rv; } // some bureaucracy... stage#, state, start time, triggers - List> createDeltasToRecordStageOpen(AccessCertificationCampaignType campaign, - AccessCertificationStageType newStage) throws ObjectNotFoundException, SchemaException, ObjectAlreadyExistsException { + private List> createDeltasToRecordStageOpen(AccessCertificationCampaignType campaign, + AccessCertificationStageType newStage) throws SchemaException { final List> itemDeltaList = new ArrayList<>(); @@ -376,8 +381,8 @@ public List getReviewerAndDeputies(ObjectReferenceType actu public void delegateWorkItems(String campaignOid, List workItems, DelegateWorkItemActionType delegateAction, Task task, OperationResult result) - throws SchemaException, ObjectNotFoundException, ObjectAlreadyExistsException, ExpressionEvaluationException, - SecurityViolationException { + throws SchemaException, ObjectNotFoundException, ObjectAlreadyExistsException, + SecurityViolationException { LOGGER.info("Going to delegate {} work item(s) in campaign {}", workItems.size(), campaignOid); MidPointPrincipal principal = securityContextManager.getPrincipal(); @@ -461,7 +466,7 @@ public void escalateCampaign(String campaignOid, EscalateWorkItemActionType esca LOGGER.info("Going to escalate the campaign {}: {} work item(s)", campaignOid, workItems.size()); XMLGregorianCalendar now = clock.currentTimeXMLGregorianCalendar(); - List> deltas = new ArrayList<>(); + ModificationsToExecute modifications = new ModificationsToExecute(); // Currently we expect all open certification work items for a given campaign to have the same escalation level. // Because of consistence with other parts of midPoint we store the escalation level within work item itself. // But we enforce it to be the same for all the open work items. @@ -511,25 +516,26 @@ public void escalateCampaign(String campaignOid, EscalateWorkItemActionType esca event.setWorkItemId(workItem.getId()); event.setEscalationLevel(workItem.getEscalationLevel()); + List> deltas = new ArrayList<>(); addDeltasForAssigneesAndEvent(deltas, workItem, aCase, newAssignees, event); deltas.add(DeltaBuilder.deltaFor(AccessCertificationCampaignType.class, prismContext) .item(F_CASE, aCase.getId(), F_WORK_ITEM, workItem.getId(), F_ESCALATION_LEVEL).replace(newEscalationLevel) .asItemDelta()); - + modifications.add(deltas); // notification (after modifications) } AccessCertificationStageType stage = CertCampaignTypeUtil.getCurrentStage(campaign); assert stage != null; Long stageId = stage.asPrismContainerValue().getId(); assert stageId != null; - deltas.add(DeltaBuilder.deltaFor(AccessCertificationCampaignType.class, prismContext) + modifications.add(DeltaBuilder.deltaFor(AccessCertificationCampaignType.class, prismContext) .item(F_STAGE, stageId, AccessCertificationStageType.F_ESCALATION_LEVEL).replace(newEscalationLevel) .asItemDelta()); AccessCertificationStageDefinitionType stageDefinition = CertCampaignTypeUtil.getCurrentStageDefinition(campaign); - deltas.addAll(createTriggersForTimedActions(campaignOid, newStageEscalationLevelNumber, + modifications.add(createTriggersForTimedActions(campaignOid, newStageEscalationLevelNumber, XmlTypeConverter.toDate(stage.getStartTimestamp()), XmlTypeConverter.toDate(stage.getDeadline()), stageDefinition.getTimedActions())); - modifyObjectViaModel(AccessCertificationCampaignType.class, campaignOid, deltas, task, result); + modifyCampaignViaModel(campaignOid, modifications, task, result); campaign = generalHelper.getCampaign(campaignOid, null, task, result); // TODO differentiate between "old" and "new" reviewers @@ -555,11 +561,9 @@ private void addDeltasForAssigneesAndEvent(List> deltas, AccessC private List computeDelegateTo(DelegateWorkItemActionType delegateAction, AccessCertificationWorkItemType workItem, AccessCertificationCaseType aCase, - AccessCertificationCampaignType campaign, Task task, OperationResult result) - throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException { + AccessCertificationCampaignType campaign, Task task, OperationResult result) { - List rv = new ArrayList<>(); - rv.addAll(CloneUtil.cloneCollectionMembers(delegateAction.getApproverRef())); + List rv = CloneUtil.cloneCollectionMembers(delegateAction.getApproverRef()); if (!delegateAction.getApproverExpression().isEmpty()) { ExpressionVariables variables = new ExpressionVariables(); variables.addVariableDefinition(ExpressionConstants.VAR_WORK_ITEM, workItem); @@ -601,18 +605,19 @@ private List computeDelegateTo(DelegateWorkItemActionType d //region ================================ Campaign and stage close ================================ - void closeCampaign(AccessCertificationCampaignType campaign, Task task, OperationResult result) throws ObjectAlreadyExistsException, ObjectNotFoundException, SchemaException, SecurityViolationException { + void closeCampaign(AccessCertificationCampaignType campaign, Task task, OperationResult result) throws ObjectAlreadyExistsException, ObjectNotFoundException, SchemaException { LOGGER.info("Closing campaign {}", ObjectTypeUtil.toShortString(campaign)); XMLGregorianCalendar now = XmlTypeConverter.createXMLGregorianCalendar(new Date()); int lastStageNumber = CertCampaignTypeUtil.getNumberOfStages(campaign); // TODO issue a warning if we are not in a correct state - List> deltas = new ArrayList<>(); - deltas.add(createStageNumberDelta(lastStageNumber + 1)); - deltas.add(createStateDelta(CLOSED)); - deltas.add(createTriggerDeleteDelta()); - deltas.add(createEndTimeDelta(now)); - deltas.addAll(createWorkItemsCloseDeltas(campaign, now, result)); - modifyObjectViaModel(AccessCertificationCampaignType.class, campaign.getOid(), deltas, task, result); + ModificationsToExecute modifications = new ModificationsToExecute(); + modifications.add(createStageNumberDelta(lastStageNumber + 1)); + modifications.add(createStateDelta(CLOSED)); + modifications.add(createTriggerDeleteDelta()); + modifications.add(createEndTimeDelta(now)); + createWorkItemsCloseDeltas(campaign, modifications, now, result); + + modifyCampaignViaModel(campaign.getOid(), modifications, task, result); AccessCertificationCampaignType updatedCampaign = refreshCampaign(campaign, result); LOGGER.info("Updated campaign state: {}", updatedCampaign.getState()); @@ -626,30 +631,31 @@ void closeCampaign(AccessCertificationCampaignType campaign, Task task, Operatio } } - private Collection> createWorkItemsCloseDeltas(AccessCertificationCampaignType campaign, + private void createWorkItemsCloseDeltas(AccessCertificationCampaignType campaign, ModificationsToExecute modifications, XMLGregorianCalendar now, OperationResult result) throws SchemaException, ObjectNotFoundException { ObjectQuery query = CertCampaignTypeUtil.createWorkItemsForCampaignQuery(campaign.getOid(), prismContext); List openWorkItems = queryHelper.searchOpenWorkItems(query, null, false, null, result); LOGGER.debug("There are {} open work items for {}", openWorkItems.size(), ObjectTypeUtil.toShortString(campaign)); - Collection> deltas = new ArrayList<>(); for (AccessCertificationWorkItemType workItem : openWorkItems) { AccessCertificationCaseType aCase = CertCampaignTypeUtil.getCaseChecked(workItem); - deltas.add( + modifications.add( DeltaBuilder.deltaFor(AccessCertificationCampaignType.class, prismContext) .item(F_CASE, aCase.getId(), F_WORK_ITEM, workItem.getId(), F_CLOSE_TIMESTAMP) .replace(now) .asItemDelta()); } - return deltas; } - List> getDeltasForStageClose(AccessCertificationCampaignType campaign, OperationResult result) throws ObjectNotFoundException, SchemaException, ObjectAlreadyExistsException { + ModificationsToExecute getDeltasForStageClose(AccessCertificationCampaignType campaign, OperationResult result) throws ObjectNotFoundException, SchemaException { XMLGregorianCalendar now = XmlTypeConverter.createXMLGregorianCalendar(new Date()); - List> rv = caseHelper.createOutcomeDeltas(campaign, result); + ModificationsToExecute rv = new ModificationsToExecute(); + caseHelper.createOutcomeDeltas(campaign, rv, result); + rv.createNewBatch(); + createWorkItemsCloseDeltas(campaign, rv, now, result); + rv.createNewBatch(); rv.add(createStateDelta(REVIEW_STAGE_DONE)); rv.add(createStageEndTimeDelta(campaign, now)); rv.add(createTriggerDeleteDelta()); - rv.addAll(createWorkItemsCloseDeltas(campaign, now, result)); return rv; } @@ -828,7 +834,17 @@ void addObject(ObjectType objectType, Task task, OperationResult result) throws */ } - void modifyObjectViaModel(Class objectClass, String oid, Collection> itemDeltas, Task task, OperationResult result) throws ObjectAlreadyExistsException, SchemaException, ObjectNotFoundException { + void modifyCampaignViaModel(String campaignOid, ModificationsToExecute modifications, Task task, OperationResult result) + throws ObjectAlreadyExistsException, SchemaException, ObjectNotFoundException { + for (List> batch : modifications.batches) { + if (!batch.isEmpty()) { + LOGGER.trace("Applying {} changes to campaign {}", batch.size(), campaignOid); + modifyObjectViaModel(AccessCertificationCampaignType.class, campaignOid, batch, task, result); + } + } + } + + void modifyObjectViaModel(Class objectClass, String oid, Collection> itemDeltas, Task task, OperationResult result) throws ObjectAlreadyExistsException, SchemaException, ObjectNotFoundException { ObjectDelta objectDelta = ObjectDelta.createModifyDelta(oid, itemDeltas, objectClass, prismContext); try { ModelExecuteOptions options = ModelExecuteOptions.createRaw().setPreAuthorized(); @@ -844,7 +860,7 @@ void modifyObjectViaModel(Class objectClass, String oi // TODO implement more efficiently public AccessCertificationCampaignType refreshCampaign(AccessCertificationCampaignType campaign, - OperationResult result) throws ObjectNotFoundException, SchemaException, SecurityViolationException { + OperationResult result) throws ObjectNotFoundException, SchemaException { return repositoryService.getObject(AccessCertificationCampaignType.class, campaign.getOid(), null, result).asObjectable(); } diff --git a/model/certification-impl/src/main/java/com/evolveum/midpoint/certification/impl/CertificationManagerImpl.java b/model/certification-impl/src/main/java/com/evolveum/midpoint/certification/impl/CertificationManagerImpl.java index b7ca38a5b06..6f6ed4dc5fa 100644 --- a/model/certification-impl/src/main/java/com/evolveum/midpoint/certification/impl/CertificationManagerImpl.java +++ b/model/certification-impl/src/main/java/com/evolveum/midpoint/certification/impl/CertificationManagerImpl.java @@ -102,6 +102,8 @@ public class CertificationManagerImpl implements CertificationManager { public static final String OPERATION_GET_CAMPAIGN_STATISTICS = INTERFACE_DOT + "getCampaignStatistics"; public static final String OPERATION_CLEANUP_CAMPAIGNS = INTERFACE_DOT + "cleanupCampaigns"; + private static final int CASES_DELTAS_BATCH_SIZE = 60; // there are 6 deltas for single case modification (TODO) + @Autowired private PrismContext prismContext; @Autowired @Qualifier("cacheRepositoryService") private RepositoryService repositoryService; @Autowired private ModelService modelService; @@ -256,8 +258,8 @@ public void openNextStage(String campaignOid, int requestedStageNumber, Task tas } else { final CertificationHandler handler = findCertificationHandler(campaign); final AccessCertificationStageType stage = updateHelper.createStage(campaign, currentStageNumber+1); - final List> deltas = updateHelper.getDeltasForStageOpen(campaign, stage, handler, task, result); - updateHelper.modifyObjectViaModel(AccessCertificationCampaignType.class, campaignOid, deltas, task, result); + final ModificationsToExecute modifications = updateHelper.getDeltasForStageOpen(campaign, stage, handler, task, result); + updateHelper.modifyCampaignViaModel(campaignOid, modifications, task, result); updateHelper.afterStageOpen(campaignOid, stage, task, result); } } catch (RuntimeException e) { @@ -299,8 +301,8 @@ public void closeCurrentStage(String campaignOid, int stageNumberToClose, Task t } else if (!IN_REVIEW_STAGE.equals(state)) { result.recordFatalError("Couldn't close review stage " + stageNumberToClose + " as it is currently not open"); } else { - List> deltas = updateHelper.getDeltasForStageClose(campaign, result); - updateHelper.modifyObjectViaModel(AccessCertificationCampaignType.class, campaignOid, deltas, task, result); + ModificationsToExecute modifications = updateHelper.getDeltasForStageClose(campaign, result); + updateHelper.modifyCampaignViaModel(campaignOid, modifications, task, result); updateHelper.afterStageClose(campaignOid, task, result); } } catch (RuntimeException e) { @@ -311,7 +313,7 @@ public void closeCurrentStage(String campaignOid, int stageNumberToClose, Task t } } - @Override + @Override public void startRemediation(String campaignOid, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, SecurityViolationException, ObjectAlreadyExistsException, ExpressionEvaluationException, CommunicationException, ConfigurationException { Validate.notNull(campaignOid, "campaignOid"); Validate.notNull(task, "task"); diff --git a/model/certification-impl/src/main/java/com/evolveum/midpoint/certification/impl/ModificationsToExecute.java b/model/certification-impl/src/main/java/com/evolveum/midpoint/certification/impl/ModificationsToExecute.java new file mode 100644 index 00000000000..3d97cfb6d71 --- /dev/null +++ b/model/certification-impl/src/main/java/com/evolveum/midpoint/certification/impl/ModificationsToExecute.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2010-2018 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.certification.impl; + +import com.evolveum.midpoint.prism.delta.ItemDelta; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * Modifications to execute on an object (mostly on a campaign). + * + * Because there can be lots of modifications that could take literally hours to execute (sometimes blocking DB as described + * e.g. in MID-4611), they are divided into smaller batches. + * + * @author mederly + */ +public class ModificationsToExecute { + + public static final int BATCH_SIZE = 50; + + public final List>> batches = new ArrayList<>(); + + public List> getLastBatch() { + return batches.get(batches.size() - 1); + } + + public boolean isEmpty() { + return batches.isEmpty(); + } + + public void add(ItemDelta... deltas) { + add(Arrays.asList(deltas)); + } + + public void add(Collection> deltas) { + if (deltas.isEmpty()) { + return; + } + if (isEmpty() || getLastBatch().size() + deltas.size() > BATCH_SIZE) { + createNewBatch(); + } + getLastBatch().addAll(deltas); + } + + public void createNewBatch() { + batches.add(new ArrayList<>()); + } + + public int getTotalDeltasCount() { + int rv = 0; + for (List> batch : batches) { + rv += batch.size(); + } + return rv; + } + + public List> getAllDeltas() { + return batches.stream().flatMap(Collection::stream).collect(Collectors.toList()); + } +} diff --git a/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/QueryInterpreter2Test.java b/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/QueryInterpreter2Test.java index b17b20ab2fe..fb3f03d571b 100644 --- a/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/QueryInterpreter2Test.java +++ b/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/QueryInterpreter2Test.java @@ -24,7 +24,6 @@ import com.evolveum.midpoint.prism.util.PrismTestUtil; import com.evolveum.midpoint.prism.xml.XmlTypeConverter; import com.evolveum.midpoint.repo.sql.data.common.any.RExtItem; -import com.evolveum.midpoint.repo.sql.data.common.dictionary.ExtItemDictionary; import com.evolveum.midpoint.repo.sql.query.QueryException; import com.evolveum.midpoint.repo.sql.query.RQuery; import com.evolveum.midpoint.repo.sql.query2.QueryEngine2; @@ -34,6 +33,7 @@ import com.evolveum.midpoint.repo.sql.util.RUtil; import com.evolveum.midpoint.schema.GetOperationOptions; import com.evolveum.midpoint.schema.MidPointPrismContextFactory; +import com.evolveum.midpoint.schema.SearchResultList; import com.evolveum.midpoint.schema.SelectorOptions; import com.evolveum.midpoint.schema.constants.MidPointConstants; import com.evolveum.midpoint.schema.constants.ObjectTypes; @@ -4754,12 +4754,13 @@ public void test1220IgnorableDistinctAndOrderBy() throws Exception { @Test public void test1230ApplicableDistinctAndOrderBy() throws Exception { + ObjectQuery query = QueryBuilder.queryFor(UserType.class, prismContext) + .item(UserType.F_EMPLOYEE_TYPE).startsWith("e") + .asc(UserType.F_NAME) + .build(); + Session session = open(); try { - ObjectQuery query = QueryBuilder.queryFor(UserType.class, prismContext) - .item(UserType.F_EMPLOYEE_TYPE).startsWith("e") - .asc(UserType.F_NAME) - .build(); String real = getInterpretedQuery2(session, UserType.class, query, false, distinct()); String expected; SqlRepositoryConfiguration config = getConfiguration(); @@ -4772,8 +4773,7 @@ public void test1230ApplicableDistinctAndOrderBy() throws Exception { + " u.datesCount,\n" + " u.referencesCount,\n" + " u.polysCount,\n" - + " u.booleansCount,\n" - + " u.nameCopy.orig\n" + + " u.booleansCount\n" + "from\n" + " RUser u\n" + "where\n" @@ -4781,7 +4781,7 @@ public void test1230ApplicableDistinctAndOrderBy() throws Exception { + " select distinct\n" + " u.oid\n" + " from\n" - + " RUser u left join u.employeeType e where e like :e )\n" + + " RUser u left join u.employeeType e where e like :e)\n" + "order by u.nameCopy.orig asc"; } else { expected = "select distinct\n" @@ -4802,6 +4802,11 @@ public void test1230ApplicableDistinctAndOrderBy() throws Exception { } finally { close(session); } + + SearchResultList> objects = repositoryService + .searchObjects(UserType.class, query, null, new OperationResult("dummy")); + System.out.println("objects: " + objects); + // just to know if the execution was successful } @Test @@ -4839,7 +4844,7 @@ public void test1240DistinctUserWithAssignment() throws Exception { + " a.targetRef.targetOid = :targetOid and\n" + " a.targetRef.relation in (:relation)\n" + " ))\n" - + "order by u.name.orig asc"; + + "order by u.nameCopy.orig asc"; } else { expected = "select distinct\n" + " u.oid,\n" diff --git a/tools/ninja/src/main/java/com/evolveum/midpoint/ninja/opts/BaseOptions.java b/tools/ninja/src/main/java/com/evolveum/midpoint/ninja/opts/BaseOptions.java index b89c7c8b5eb..e45306cfcdd 100644 --- a/tools/ninja/src/main/java/com/evolveum/midpoint/ninja/opts/BaseOptions.java +++ b/tools/ninja/src/main/java/com/evolveum/midpoint/ninja/opts/BaseOptions.java @@ -19,6 +19,8 @@ import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; +import java.io.File; + /** * Created by Viliam Repan (lazyman). */ @@ -40,6 +42,12 @@ public class BaseOptions { public static final String P_VERSION = "-V"; public static final String P_VERSION_LONG = "--version"; + public static final String P_JDBC = "-j"; + public static final String P_JDBC_LONG = "--jdbc"; + + @Parameter(names = {P_JDBC, P_JDBC_LONG}, descriptionKey = "base.jdbc", hidden = true) + private File jdbc; + @Parameter(names = {P_HELP, P_HELP_LONG}, help = true, descriptionKey = "base.help") private boolean help = false; @@ -74,4 +82,8 @@ public String getCharset() { public boolean isVersion() { return version; } + + public File getJdbc() { + return jdbc; + } } diff --git a/tools/ninja/src/main/resources/messages.properties b/tools/ninja/src/main/resources/messages.properties index 15a16afb3c7..45e970bda43 100644 --- a/tools/ninja/src/main/resources/messages.properties +++ b/tools/ninja/src/main/resources/messages.properties @@ -30,6 +30,7 @@ base.version=Version and build description base.charset=Charset used for input/output base.silent=No output at all base.verbose=Verbose output +base.jdbc=Path to JDBC Driver jar file connection.url=Url to MidPoint model webservice endpoint or JDBC url to database. If '-m' option is used url \ will be used to connect to JDBC database. If '-m' is not specified then this parameter is used as MidPoint \ REST url endpoint. diff --git a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/MidPoint.java b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/MidPoint.java index 138476a8834..fcf9890f0b2 100644 --- a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/MidPoint.java +++ b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/MidPoint.java @@ -25,7 +25,7 @@ public MidPoint(EnvironmentConfiguration environment) { private void init() { environment.validate(); - //System.setProperty("webdriver.chrome.driver","C:\\Users\\matus\\chromedriver\\chromedriver.exe"); // TODO workaround, find proper way how to resolve + // System.setProperty("webdriver.chrome.driver","C:\\Users\\matus\\chromedriver\\chromedriver.exe"); // TODO workaround, find proper way how to resolve System.setProperty("selenide.browser", environment.getDriver().name().toLowerCase()); System.setProperty("selenide.baseUrl", environment.getBaseUrl()); diff --git a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/common/Popover.java b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/common/Popover.java index 23bc44d6536..57e8bf14ce5 100644 --- a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/common/Popover.java +++ b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/common/Popover.java @@ -18,7 +18,7 @@ public Popover(T parent, SelenideElement parentElement) { } public Popover inputValue(String input) { - getParentElement().$(By.cssSelector("input.form-control.input-sm")).setValue(input); + getParentElement().$(Schrodinger.byDataId("textInput")).waitUntil(Condition.appears, MidPoint.TIMEOUT_DEFAULT).setValue(input); return this; } diff --git a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/common/PrismForm.java b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/common/PrismForm.java index d590fd645c8..04b3653a70d 100644 --- a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/common/PrismForm.java +++ b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/common/PrismForm.java @@ -101,6 +101,27 @@ public PrismForm showEmptyAttributes(String containerName) { return this; } + public Boolean compareAttibuteValue(String name, String expectedValue) { + SelenideElement property = findProperty(name); + SelenideElement value = property.$(By.xpath(".//input[contains(@class,\"form-control\")]")); + String valueElemen = value.getValue(); + + if (!valueElemen.isEmpty()) { + + return valueElemen.equals(expectedValue); + + } else if (!expectedValue.isEmpty()) { + + return false; + + } else { + + return true; + + } + + } + public PrismForm addAttributeValue(QName name, String value) { SelenideElement property = findProperty(name); @@ -155,10 +176,10 @@ private SelenideElement findProperty(String name) { if (doesElementAttrValueExist) { element = $(Schrodinger.byElementAttributeValue(null, "contains", - Schrodinger.DATA_S_QNAME, "#" + name)); + Schrodinger.DATA_S_QNAME, "#" + name)).waitUntil(Condition.appear, MidPoint.TIMEOUT_DEFAULT); } else { - element = $(By.xpath("//span[@data-s-id=\"label\"][text()=\"" + name + "\"]/..")) + element = $(By.xpath("//span[@data-s-id=\"label\"][contains(.,\"" + name + "\")]/..")) .waitUntil(Condition.appears, MidPoint.TIMEOUT_DEFAULT).parent(); } diff --git a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/common/Search.java b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/common/Search.java index ae9dec6f93a..19a65cea0d6 100644 --- a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/common/Search.java +++ b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/common/Search.java @@ -45,6 +45,7 @@ public Popover> byName() { popover = popoverElement; break; } + popover = popoverElement; } return new Popover<>(this, popover); } diff --git a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/common/table/AbstractTable.java b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/common/table/AbstractTable.java index d28e017f097..0d82a34ca51 100644 --- a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/common/table/AbstractTable.java +++ b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/common/table/AbstractTable.java @@ -7,6 +7,7 @@ * Created by matus on 5/9/2018. */ public abstract class AbstractTable extends Table { + public AbstractTable(T parent, SelenideElement parentElement) { super(parent, parentElement); } diff --git a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/common/table/InputTable.java b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/common/table/InputTable.java new file mode 100644 index 00000000000..b5b560fc2cb --- /dev/null +++ b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/common/table/InputTable.java @@ -0,0 +1,38 @@ +package com.evolveum.midpoint.schrodinger.component.common.table; + +import com.codeborne.selenide.Condition; +import com.codeborne.selenide.SelenideElement; +import com.evolveum.midpoint.schrodinger.MidPoint; +import com.evolveum.midpoint.schrodinger.component.Component; +import com.evolveum.midpoint.schrodinger.util.Schrodinger; + +import static com.codeborne.selenide.Selenide.$; + +/** + * Created by matus on 5/22/2018. + */ +public class InputTable extends Component{ + public InputTable(T parent, SelenideElement parentElement) { + super(parent, parentElement); + } + + public InputTable addAttributeValue(String attributeName, String attributeValue){ + System.out.println("The inner html: " + getParentElement().innerHtml()); + + SelenideElement element = $(Schrodinger.byAncestorPrecedingSiblingElementValue("input","type","text",null,null,attributeName)) + .waitUntil(Condition.appears, MidPoint.TIMEOUT_DEFAULT).setValue(attributeValue); + + return this; + } + + + public InputTable clickCheckBox(String attributeName){ + + $(Schrodinger.byAncestorPrecedingSiblingElementValue("input","type","checkbox",null,null,attributeName)) + .waitUntil(Condition.appears, MidPoint.TIMEOUT_DEFAULT).click(); + + return this; + } + + +} diff --git a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/common/table/Table.java b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/common/table/Table.java index eec100a9f37..9adc760bec5 100644 --- a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/common/table/Table.java +++ b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/common/table/Table.java @@ -60,6 +60,6 @@ public Table selectAll() { public boolean currentTableContains(String name) { - return $(Schrodinger.byElementValue("Span", name)).waitUntil(Condition.appears, MidPoint.TIMEOUT_DEFAULT).is(Condition.visible); + return $(Schrodinger.byElementValue("Span", name)).is(Condition.visible); } } diff --git a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/resource/ResourceAccountsTab.java b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/resource/ResourceAccountsTab.java new file mode 100644 index 00000000000..56bced8e317 --- /dev/null +++ b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/resource/ResourceAccountsTab.java @@ -0,0 +1,86 @@ +package com.evolveum.midpoint.schrodinger.component.resource; + +import com.codeborne.selenide.Condition; +import com.codeborne.selenide.ElementsCollection; +import com.codeborne.selenide.SelenideElement; +import com.evolveum.midpoint.schrodinger.MidPoint; +import com.evolveum.midpoint.schrodinger.component.Component; +import com.evolveum.midpoint.schrodinger.util.Schrodinger; +import org.openqa.selenium.By; + +import static com.codeborne.selenide.Selenide.$; +import static com.codeborne.selenide.Selenide.$$; + +/** + * Created by matus on 5/22/2018. + */ +public class ResourceAccountsTab extends Component { + public ResourceAccountsTab(T parent, SelenideElement parentElement) { + super(parent, parentElement); + } + + public ResourceTaskQuickAccessDropDown> importTask() { + $(Schrodinger.byElementAttributeValue("label", "data-s-id", "label", "Import")) + .waitUntil(Condition.appears, MidPoint.TIMEOUT_DEFAULT).click(); + + SelenideElement dropDownElement = $(Schrodinger.byElementAttributeValue("ul", "role", "menu")) + .waitUntil(Condition.appears, MidPoint.TIMEOUT_DEFAULT); + + return new ResourceTaskQuickAccessDropDown<>(this, dropDownElement); + } + + public ResourceTaskQuickAccessDropDown> reconciliationTask() { + $(Schrodinger.byElementAttributeValue("label", "data-s-id", "label", "Reconciliation")) + .waitUntil(Condition.appears, MidPoint.TIMEOUT_DEFAULT).click(); + + SelenideElement dropDownElement = $(Schrodinger.byElementAttributeValue("ul", "role", "menu")) + .waitUntil(Condition.appears, MidPoint.TIMEOUT_DEFAULT); + + return new ResourceTaskQuickAccessDropDown<>(this, dropDownElement); + } + + public ResourceTaskQuickAccessDropDown> liveSyncTask() { + $(Schrodinger.byElementValue("label", "data-s-id", "label", "Live Sync")) + .waitUntil(Condition.appears, MidPoint.TIMEOUT_DEFAULT).click(); + + ElementsCollection dropDownElement = $$(By.cssSelector(".dropdown-menu.pull-right")); + + SelenideElement concretElement = null; + + for (SelenideElement element : dropDownElement) { + if (element.isDisplayed()) { + concretElement = element; + break; + } + } + return new ResourceTaskQuickAccessDropDown<>(this, concretElement); + } + + public ResourceAccountsTab clickSearchInRepository() { + + $(Schrodinger.byDataId("a", "repositorySearch")) + .waitUntil(Condition.appears, MidPoint.TIMEOUT_DEFAULT).click(); + + $(Schrodinger.byDataId("a", "repositorySearch")) + .waitUntil(Condition.enabled, MidPoint.TIMEOUT_DEFAULT); + + return this; + } + + public ResourceAccountsTab clickSearchInResource() { + $(Schrodinger.byDataId("a", "resourceSearch")) + .waitUntil(Condition.appears, MidPoint.TIMEOUT_DEFAULT).click(); + $(Schrodinger.byDataId("a", "resourceSearch")) + .waitUntil(Condition.enabled, MidPoint.TIMEOUT_DEFAULT); + return this; + } + + public ResourceShadowTable> table() { + + SelenideElement element = $(By.cssSelector(".box.boxed-table.object-shadow-box")) + .waitUntil(Condition.appears, MidPoint.TIMEOUT_DEFAULT); + + return new ResourceShadowTable<>(this, element); + } + +} diff --git a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/resource/ResourceShadowTable.java b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/resource/ResourceShadowTable.java new file mode 100644 index 00000000000..fbc10422600 --- /dev/null +++ b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/resource/ResourceShadowTable.java @@ -0,0 +1,46 @@ +package com.evolveum.midpoint.schrodinger.component.resource; + +import com.codeborne.selenide.Condition; +import com.codeborne.selenide.SelenideElement; +import com.evolveum.midpoint.schrodinger.MidPoint; +import com.evolveum.midpoint.schrodinger.component.common.DropDown; +import com.evolveum.midpoint.schrodinger.component.common.table.TableWithPageRedirect; +import com.evolveum.midpoint.schrodinger.page.BasicPage; +import com.evolveum.midpoint.schrodinger.util.Schrodinger; +import org.openqa.selenium.By; + +import static com.codeborne.selenide.Selenide.$; + +/** + * Created by matus on 5/25/2018. + */ +public class ResourceShadowTable extends TableWithPageRedirect { + public ResourceShadowTable(T parent, SelenideElement parentElement) { + super(parent, parentElement); + } + + @Override + public E clickByName(String name) { + return null; + } + + @Override + public ResourceShadowTable selectCheckboxByName(String name) { + + $(Schrodinger.byAncestorFollowingSiblingElementValue("input", "type", "checkbox", "data-s-id", "1", name)) + .waitUntil(Condition.appears, MidPoint.TIMEOUT_DEFAULT).click(); + return this; + } + + public ResourceShadowTableCog> clickCog() { + + $(Schrodinger.byElementAttributeValue("a", "about", "dropdownMenu")) + .waitUntil(Condition.appears, MidPoint.TIMEOUT_DEFAULT).click(); + + SelenideElement cog = $(By.cssSelector(".dropdown-menu.pull-right")) + .waitUntil(Condition.appears, MidPoint.TIMEOUT_DEFAULT); + + return new ResourceShadowTableCog<>(this, cog); + } + +} diff --git a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/resource/ResourceShadowTableCog.java b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/resource/ResourceShadowTableCog.java new file mode 100644 index 00000000000..d65a1d9210a --- /dev/null +++ b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/resource/ResourceShadowTableCog.java @@ -0,0 +1,59 @@ +package com.evolveum.midpoint.schrodinger.component.resource; + +import com.codeborne.selenide.Condition; +import com.codeborne.selenide.SelenideElement; +import com.evolveum.midpoint.schrodinger.MidPoint; +import com.evolveum.midpoint.schrodinger.component.common.ConfirmationModal; +import com.evolveum.midpoint.schrodinger.component.common.DropDown; +import com.evolveum.midpoint.schrodinger.util.Schrodinger; + +import static com.codeborne.selenide.Selenide.$; + +/** + * Created by matus on 5/25/2018. + */ +public class ResourceShadowTableCog extends DropDown { + public ResourceShadowTableCog(T parent, SelenideElement parentElement) { + super(parent, parentElement); + } + + + public T clickEnable() { + $(Schrodinger.byDataResourceKey("pageContentAccounts.menu.enableAccounts")) + .parent().waitUntil(Condition.appears, MidPoint.TIMEOUT_DEFAULT).click(); + + return this.getParent(); + } + + public T clickDisable() { + $(Schrodinger.byDataResourceKey("pageContentAccounts.menu.disableAccounts")) + .parent().waitUntil(Condition.appears, MidPoint.TIMEOUT_DEFAULT).click(); + + return this.getParent(); + } + + public ConfirmationModal clickDelete() { + $(Schrodinger.byDataResourceKey("pageContentAccounts.menu.deleteAccounts")) + .parent().waitUntil(Condition.appears, MidPoint.TIMEOUT_DEFAULT).click(); + + SelenideElement modalBox = $(Schrodinger.byElementAttributeValue("div", "aria-labelledby", "Confirm deletion")) + .waitUntil(Condition.appears, MidPoint.TIMEOUT_DEFAULT); + + return new ConfirmationModal<>(this.getParent(), modalBox); + } + + public T clickImport() { + $(Schrodinger.byDataResourceKey("pageContentAccounts.menu.importAccounts")) + .parent().waitUntil(Condition.appears, MidPoint.TIMEOUT_DEFAULT).click(); + + return this.getParent(); + } + + public T clickRemoveOwner() { + $(Schrodinger.byDataResourceKey("pageContentAccounts.menu.removeOwners")) + .parent().waitUntil(Condition.appears, MidPoint.TIMEOUT_DEFAULT).click(); + + return this.getParent(); + } + +} diff --git a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/resource/ResourceTaskQuickAccessDropDown.java b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/resource/ResourceTaskQuickAccessDropDown.java new file mode 100644 index 00000000000..57a9572c82c --- /dev/null +++ b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/resource/ResourceTaskQuickAccessDropDown.java @@ -0,0 +1,43 @@ +package com.evolveum.midpoint.schrodinger.component.resource; + +import com.codeborne.selenide.Condition; +import com.codeborne.selenide.ElementsCollection; +import com.codeborne.selenide.SelenideElement; +import com.evolveum.midpoint.schrodinger.MidPoint; +import com.evolveum.midpoint.schrodinger.component.common.DropDown; +import com.evolveum.midpoint.schrodinger.page.task.NewTaskPage; +import com.evolveum.midpoint.schrodinger.util.Schrodinger; + +import static com.codeborne.selenide.Selenide.$; +import static com.codeborne.selenide.Selenide.$$; + +/** + * Created by matus on 5/22/2018. + */ +public class ResourceTaskQuickAccessDropDown extends DropDown { + public ResourceTaskQuickAccessDropDown(T parent, SelenideElement parentElement) { + super(parent, parentElement); + } + + public T clickShowExisting() { + $(Schrodinger.byDataResourceKey("schrodinger", "ResourceContentResourcePanel.showExisting")).parent() + .click(); + + return this.getParent(); + } + + public NewTaskPage clickCreateNew() { + + ElementsCollection elements = $$(Schrodinger.byElementValue("a", "data-s-id", "menuItemLink", "Create new")); + for (SelenideElement element : elements) { + + if (element.isDisplayed()) { + element.click(); + break; + } + } + + return new NewTaskPage(); + } + +} diff --git a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/resource/ResourcesTablePage.java b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/resource/ResourcesPageTable.java similarity index 62% rename from tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/resource/ResourcesTablePage.java rename to tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/resource/ResourcesPageTable.java index 873b928d602..0a3c6a75391 100644 --- a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/resource/ResourcesTablePage.java +++ b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/resource/ResourcesPageTable.java @@ -3,24 +3,27 @@ import com.codeborne.selenide.Condition; import com.codeborne.selenide.SelenideElement; import com.evolveum.midpoint.schrodinger.MidPoint; +import com.evolveum.midpoint.schrodinger.component.common.Search; import com.evolveum.midpoint.schrodinger.component.common.table.TableWithPageRedirect; import com.evolveum.midpoint.schrodinger.page.resource.ViewResourcePage; import com.evolveum.midpoint.schrodinger.util.Schrodinger; +import org.openqa.selenium.By; + +import static com.codeborne.selenide.Selenide.$; /** * Created by matus on 4/25/2018. */ -public class ResourcesTablePage extends TableWithPageRedirect { - public ResourcesTablePage(T parent, SelenideElement parentElement) { +public class ResourcesPageTable extends TableWithPageRedirect { + public ResourcesPageTable(T parent, SelenideElement parentElement) { super(parent, parentElement); } @Override public TableWithPageRedirect selectCheckboxByName(String name) { - return null; + return this; } - @Override public ViewResourcePage clickByName(String name) { getParentElement().$(Schrodinger.byElementValue("span", "data-s-id", "label", name)) @@ -28,4 +31,11 @@ public ViewResourcePage clickByName(String name) { return new ViewResourcePage(); } + + @Override + public Search> search() { + SelenideElement searchElement = getParentElement().$(By.cssSelector(".form-inline.pull-right.search-form")); + + return new Search<>(this, searchElement); + } } diff --git a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/self/QuickSearch.java b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/self/QuickSearch.java index f3264cb39d6..300332bff59 100644 --- a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/self/QuickSearch.java +++ b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/self/QuickSearch.java @@ -4,10 +4,8 @@ import com.codeborne.selenide.SelenideElement; import com.evolveum.midpoint.schrodinger.MidPoint; import com.evolveum.midpoint.schrodinger.component.Component; -import com.evolveum.midpoint.schrodinger.component.common.DropDown; import com.evolveum.midpoint.schrodinger.component.common.table.Table; import com.evolveum.midpoint.schrodinger.util.Schrodinger; -import org.openqa.selenium.By; import static com.codeborne.selenide.Selenide.$; @@ -19,26 +17,26 @@ public QuickSearch(T parent, SelenideElement parentElement) { super(parent, parentElement); } - public QuickSearch inputValue(String name){ - $(Schrodinger.byElementAttributeValue("input","name","searchInput")).setValue(name); + public QuickSearch inputValue(String name) { + $(Schrodinger.byElementAttributeValue("input", "name", "searchInput")).setValue(name); return this; } //TODO rethink - public Table clickSearch(){ - $(Schrodinger.byElementAttributeValue("button","data-s-id","searchButton")) + public Table clickSearch() { + $(Schrodinger.byElementAttributeValue("button", "data-s-id", "searchButton")) .click(); - return new Table("null",null); + return new Table("null", null); } - public QuickSearchDropDown> clickSearchFor(){ - $(Schrodinger.bySelfOrDescendantElementAttributeValue("button","data-toggle","dropdown","class","sr-only")) - .waitUntil(Condition.appears,MidPoint.TIMEOUT_DEFAULT).click(); - SelenideElement dropDown = $(Schrodinger.byElementAttributeValue("ul","role","menu")) - .waitUntil(Condition.visible,MidPoint.TIMEOUT_DEFAULT); + public QuickSearchDropDown> clickSearchFor() { + $(Schrodinger.byDescendantOrSelfElementAttributeValue("button", "data-toggle", "dropdown", "class", "sr-only")) + .waitUntil(Condition.appears, MidPoint.TIMEOUT_DEFAULT).click(); + SelenideElement dropDown = $(Schrodinger.byElementAttributeValue("ul", "role", "menu")) + .waitUntil(Condition.visible, MidPoint.TIMEOUT_DEFAULT); - return new QuickSearchDropDown<>(this,dropDown); + return new QuickSearchDropDown<>(this, dropDown); } } diff --git a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/user/UserAssignmentsTab.java b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/user/UserAssignmentsTab.java index e2f78113946..91e77c83b28 100644 --- a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/user/UserAssignmentsTab.java +++ b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/user/UserAssignmentsTab.java @@ -22,7 +22,6 @@ import com.evolveum.midpoint.schrodinger.component.Component; import com.evolveum.midpoint.schrodinger.component.FocusSetAssignmentsModal; import com.evolveum.midpoint.schrodinger.component.common.PrismFormWithActionButtons; -import com.evolveum.midpoint.schrodinger.component.common.table.AbstractTable; import com.evolveum.midpoint.schrodinger.component.common.table.AbstractTableWithPrismView; import com.evolveum.midpoint.schrodinger.page.user.UserPage; import com.evolveum.midpoint.schrodinger.util.Schrodinger; @@ -58,7 +57,7 @@ public PrismFormWithActionButtons @Override public AbstractTableWithPrismView selectCheckboxByName(String name) { - $(Schrodinger.byFollowingSiblingElementValue("td", "class", "check", "data-s-id", "3", name)) + $(Schrodinger.byFollowingSiblingEnclosedValue("td", "class", "check", "data-s-id", "3", name)) .waitUntil(Condition.appears, MidPoint.TIMEOUT_DEFAULT).click(); return this; @@ -67,7 +66,7 @@ public AbstractTableWithPrismView selectCheckboxByName(Strin @Override public AbstractTableWithPrismView unassignByName(String name) { - $(Schrodinger.byAncestorElementValue("button", "title", "Unassign", "data-s-id", "3", name)) + $(Schrodinger.byAncestorPrecedingSiblingElementValue("button", "title", "Unassign", null, null, name)) .waitUntil(Condition.appears, MidPoint.TIMEOUT_DEFAULT).click(); return this; diff --git a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/user/UserProjectionsTab.java b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/user/UserProjectionsTab.java index 9d1a91706ea..6b31fae27f0 100644 --- a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/user/UserProjectionsTab.java +++ b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/user/UserProjectionsTab.java @@ -66,7 +66,7 @@ public PrismForm> clickByName(String name) { @Override public AbstractTable selectCheckboxByName(String name) { - $(Schrodinger.byFollowingSiblingElementValue("input", "type", "checkbox", "class", "check-table-label", name)) + $(Schrodinger.byFollowingSiblingEnclosedValue("input", "type", "checkbox", "class", "check-table-label", name)) .waitUntil(Condition.appears, MidPoint.TIMEOUT_DEFAULT).click(); return this; diff --git a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/user/UsersTablePage.java b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/user/UsersPageTable.java similarity index 89% rename from tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/user/UsersTablePage.java rename to tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/user/UsersPageTable.java index 7fb347b0abc..9eddf38272a 100644 --- a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/user/UsersTablePage.java +++ b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/component/user/UsersPageTable.java @@ -31,9 +31,9 @@ /** * Created by Viliam Repan (lazyman). */ -public class UsersTablePage extends TableWithPageRedirect { +public class UsersPageTable extends TableWithPageRedirect { - public UsersTablePage(T parent, SelenideElement parentElement) { + public UsersPageTable(T parent, SelenideElement parentElement) { super(parent, parentElement); } @@ -52,14 +52,14 @@ public UserPage clickByName(String name) { } @Override - public Search> search() { + public Search> search() { SelenideElement searchElement = getParentElement().$(By.cssSelector(".form-inline.pull-right.search-form")); return new Search<>(this, searchElement); } - public ConfirmationModal> clickEnable() { + public ConfirmationModal> clickEnable() { $(Schrodinger.bySelfOrAncestorElementAttributeValue("i", "class", "fa fa-user fa-fw", "data-s-id", "topToolbars")) .waitUntil(Condition.appears, MidPoint.TIMEOUT_DEFAULT).click(); @@ -72,7 +72,7 @@ public ConfirmationModal> clickEnable() { @Override - public UsersTablePage selectAll() { + public UsersPageTable selectAll() { $(Schrodinger.bySelfOrAncestorElementAttributeValue("input", "type", "checkbox", "data-s-id", "topToolbars")) .waitUntil(Condition.appears, MidPoint.TIMEOUT_DEFAULT).click(); @@ -80,7 +80,7 @@ public UsersTablePage selectAll() { return this; } - public UsersTableDropDown> clickActionDropDown() { + public UsersTableDropDown> clickActionDropDown() { $(Schrodinger.bySelfOrAncestorElementAttributeValue("button", "data-toggle", "dropdown", "class", "sortableLabel")) .waitUntil(Condition.appears, MidPoint.TIMEOUT_DEFAULT).click(); diff --git a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/page/resource/ListResourcesPage.java b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/page/resource/ListResourcesPage.java index a636db1ce2b..106bd60dc32 100644 --- a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/page/resource/ListResourcesPage.java +++ b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/page/resource/ListResourcesPage.java @@ -1,7 +1,7 @@ package com.evolveum.midpoint.schrodinger.page.resource; import com.codeborne.selenide.SelenideElement; -import com.evolveum.midpoint.schrodinger.component.resource.ResourcesTablePage; +import com.evolveum.midpoint.schrodinger.component.resource.ResourcesPageTable; import com.evolveum.midpoint.schrodinger.page.BasicPage; import org.openqa.selenium.By; @@ -12,9 +12,9 @@ */ public class ListResourcesPage extends BasicPage { - public ResourcesTablePage table() { + public ResourcesPageTable table() { SelenideElement table = $(By.cssSelector(".box.boxed-table.object-resource-box")); - return new ResourcesTablePage<>(this, table); + return new ResourcesPageTable<>(this, table); } } diff --git a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/page/resource/ViewResourcePage.java b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/page/resource/ViewResourcePage.java index 4e01ff0c554..0c6048d5a20 100644 --- a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/page/resource/ViewResourcePage.java +++ b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/page/resource/ViewResourcePage.java @@ -1,10 +1,15 @@ package com.evolveum.midpoint.schrodinger.page.resource; import com.codeborne.selenide.Condition; +import com.codeborne.selenide.SelenideElement; import com.evolveum.midpoint.schrodinger.MidPoint; +import com.evolveum.midpoint.schrodinger.component.common.FeedbackBox; +import com.evolveum.midpoint.schrodinger.component.resource.ResourceAccountsTab; import com.evolveum.midpoint.schrodinger.component.resource.ResourceConfigurationTab; import com.evolveum.midpoint.schrodinger.page.BasicPage; +import com.evolveum.midpoint.schrodinger.page.configuration.AboutPage; import com.evolveum.midpoint.schrodinger.util.Schrodinger; +import org.openqa.selenium.By; import static com.codeborne.selenide.Selenide.$; @@ -18,4 +23,20 @@ public ResourceConfigurationTab clickEditResourceConfiguration() { return new ResourceConfigurationTab(new EditResourceConfigurationPage(), null); } + public ResourceAccountsTab clicAccountsTab() { + + $(Schrodinger.byDataResourceKey("schrodinger", "PageResource.tab.content.account")).parent() + .waitUntil(Condition.appears, MidPoint.TIMEOUT_DEFAULT).click(); + + SelenideElement tabContent = $(By.cssSelector(".tab-pane.active")) + .waitUntil(Condition.appears, MidPoint.TIMEOUT_DEFAULT); + + return new ResourceAccountsTab<>(this, tabContent); + } + + public FeedbackBox feedback() { + SelenideElement feedback = $(By.cssSelector("div.feedbackContainer")); + + return new FeedbackBox<>(this, feedback); + } } diff --git a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/page/task/ListTasksPage.java b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/page/task/ListTasksPage.java index 4b8192e69ce..9be1251f1b3 100644 --- a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/page/task/ListTasksPage.java +++ b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/page/task/ListTasksPage.java @@ -1,9 +1,21 @@ package com.evolveum.midpoint.schrodinger.page.task; +import com.codeborne.selenide.SelenideElement; +import com.evolveum.midpoint.schrodinger.component.common.FeedbackBox; import com.evolveum.midpoint.schrodinger.page.BasicPage; +import org.openqa.selenium.By; + +import static com.codeborne.selenide.Selenide.$; /** * Created by Viliam Repan (lazyman). */ public class ListTasksPage extends BasicPage { + + public FeedbackBox feedback() { + SelenideElement feedback = $(By.cssSelector("div.feedbackContainer")); + + return new FeedbackBox<>(this, feedback); + } + } diff --git a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/page/task/NewTaskPage.java b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/page/task/NewTaskPage.java index 78eb8cee153..e28744117c9 100644 --- a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/page/task/NewTaskPage.java +++ b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/page/task/NewTaskPage.java @@ -1,10 +1,41 @@ package com.evolveum.midpoint.schrodinger.page.task; +import com.codeborne.selenide.Condition; +import com.codeborne.selenide.SelenideElement; +import com.evolveum.midpoint.schrodinger.MidPoint; +import com.evolveum.midpoint.schrodinger.component.common.table.InputTable; import com.evolveum.midpoint.schrodinger.page.BasicPage; +import com.evolveum.midpoint.schrodinger.util.Schrodinger; + +import static com.codeborne.selenide.Selenide.$; /** * Created by Viliam Repan (lazyman). */ public class NewTaskPage extends BasicPage { + public InputTable basicTable() { + + SelenideElement tableElement = $(Schrodinger.byPrecedingSiblingEnclosedValue("table", "class", "table table-condensed table-striped", null, null, "Basic")) + .waitUntil(Condition.appears, MidPoint.TIMEOUT_DEFAULT); + + return new InputTable<>(this, tableElement); + } + + public InputTable schedulingTable() { + + SelenideElement tableElement = $(Schrodinger.byPrecedingSiblingEnclosedValue("table", "class", "table table-condensed table-striped", null, null, "Scheduling")) + .waitUntil(Condition.appears, MidPoint.TIMEOUT_DEFAULT); + + return new InputTable<>(this, tableElement); + } + + public ListTasksPage clickSave() { + + $(Schrodinger.byDataId("saveButton")) + .waitUntil(Condition.appears, MidPoint.TIMEOUT_DEFAULT).click(); + + return new ListTasksPage(); + } + } diff --git a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/page/user/ListUsersPage.java b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/page/user/ListUsersPage.java index 381bbafc631..1c4d3cbb222 100644 --- a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/page/user/ListUsersPage.java +++ b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/page/user/ListUsersPage.java @@ -2,7 +2,7 @@ import com.codeborne.selenide.SelenideElement; import com.evolveum.midpoint.schrodinger.component.common.FeedbackBox; -import com.evolveum.midpoint.schrodinger.component.user.UsersTablePage; +import com.evolveum.midpoint.schrodinger.component.user.UsersPageTable; import com.evolveum.midpoint.schrodinger.page.BasicPage; import org.openqa.selenium.By; @@ -13,10 +13,10 @@ */ public class ListUsersPage extends BasicPage { - public UsersTablePage table() { + public UsersPageTable table() { SelenideElement box = $(By.cssSelector(".box.boxed-table.object-user-box")); - return new UsersTablePage<>(this, box); + return new UsersPageTable<>(this, box); } public FeedbackBox feedback() { diff --git a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/util/Schrodinger.java b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/util/Schrodinger.java index d9aecb1d5c3..8f2619d24a3 100644 --- a/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/util/Schrodinger.java +++ b/tools/schrodinger/src/main/java/com/evolveum/midpoint/schrodinger/util/Schrodinger.java @@ -77,23 +77,27 @@ public static By byElementValue(String element, String attr, String attrValue, S element = "*"; } - return By.xpath("//" + element + "[@" + attr + "=\"" + attrValue + "\"][contains(.,\"" + enclosedText + "\")]/.."); + return byElementValue(element, attr, attrValue, null, enclosedText); } - public static By byElementValue(String elementName, String value) { - if (elementName == null) { - elementName = "*"; + public static By byElementValue(String element, String attr, String attrValue, String enclosingElement, String enclosedText) { + + if (element == null) { + element = "*"; + } + if (enclosingElement == null) { + enclosingElement = "."; } - return By.xpath("//" + elementName + "[text()='" + value + "']"); + return By.xpath("//" + element + "[@" + attr + "=\"" + attrValue + "\"][contains(" + enclosingElement + ",\"" + enclosedText + "\")]/.."); } - public static By byElementValueConcrete(String elementName, String value) { + public static By byElementValue(String elementName, String value) { if (elementName == null) { elementName = "*"; } - return By.xpath("//" + elementName + "contains(.,\"" + value + "\""); + return By.xpath("//" + elementName + "[text()='" + value + "']"); } public static By bySelfOrAncestorElementAttributeValue(String element, String attr, String attrValue, String ancestorAttr, String ancestorAttrValue) { @@ -104,7 +108,7 @@ public static By bySelfOrAncestorElementAttributeValue(String element, String at return By.xpath("//" + element + "[@" + attr + "=\"" + attrValue + "\" and ancestor-or-self::*[@" + ancestorAttr + "=\"" + ancestorAttrValue + "\"]]"); } - public static By bySelfOrDescendantElementAttributeValue(String element, String attr, String attrValue, String descendantAttr, String descendantAttrValue) { + public static By byDescendantOrSelfElementAttributeValue(String element, String attr, String attrValue, String descendantAttr, String descendantAttrValue) { if (element == null) { element = "*"; } @@ -112,28 +116,80 @@ public static By bySelfOrDescendantElementAttributeValue(String element, String return By.xpath("//" + element + "[@" + attr + "=\"" + attrValue + "\" and descendant-or-self::*[@" + descendantAttr + "=\"" + descendantAttrValue + "\"]]"); } - public static By byFollowingSiblingElementValue(String element, String attr, String attrValue, String siblingAttr, String siblingAttrValue, String siblingEnclosedText) { + public static By byFollowingSiblingEnclosedValue(String element, String attr, String attrValue, String siblingAttr, String siblingAttrValue, String siblingEnclosedText) { if (element == null) { element = "*"; } - return By.xpath("//" + element + "[@" + attr + "=\"" + attrValue + "\" and following-sibling::*[@" + siblingAttr + "=\"" + siblingAttrValue + "\" and descendant::*[contains(.,\"" + siblingEnclosedText + "\")]]]"); + return By.xpath("//" + element + "[@" + attr + "=\"" + attrValue + "\" and following-sibling::*[@" + siblingAttr + "=\"" + siblingAttrValue + "\" and descendant-or-self::*[contains(.,\"" + siblingEnclosedText + "\")]]]"); } - public static By byPrecedingSiblingElementValue(String element, String attr, String attrValue, String siblingAttr, String siblingAttrValue, String siblingEnclosedText) { + public static By byPrecedingSiblingEnclosedValue(String element, String attr, String attrValue, String siblingAttr, String siblingAttrValue, String siblingEnclosedText) { if (element == null) { element = "*"; } - return By.xpath("//" + element + "[@" + attr + "=\"" + attrValue + "\" and preceding-sibling::*[@" + siblingAttr + "=\"" + siblingAttrValue + "\" and descendant::*[contains(.,\"" + siblingEnclosedText + "\")]]]"); + StringBuilder xpathBuilder = new StringBuilder("//").append(element).append("["); + + if (attr != null) { + xpathBuilder.append("@").append(attr).append("=\"").append(attrValue).append("\" and preceding-sibling::*["); + } else { + xpathBuilder.append("not(@*)").append(" and preceding-sibling::*["); + } + + if (siblingAttr != null) { + xpathBuilder.append("@").append(siblingAttr).append("=\"").append(siblingAttrValue).append("\" and descendant-or-self::*[contains(.,\"" + siblingEnclosedText + "\")]]]"); + } else { + xpathBuilder.append("not(@*)").append(" and descendant-or-self::*[contains(.,\"" + siblingEnclosedText + "\")]]]"); + } + + return By.xpath(xpathBuilder.toString()); } - public static By byAncestorElementValue(String element, String attr, String attrValue, String ancestorAttr, String ancestorAttrValue, String ancestorEnclosedText) { + public static By byAncestorPrecedingSiblingElementValue(String element, String attr, String attrValue, String ancestorAttr, String ancestorAttrValue, String ancestorEnclosedText) { if (element == null) { element = "*"; } - return By.xpath("//" + element + "[@" + attr + "=\"" + attrValue + "\" and ancestor::*[@" + ancestorAttr + "=\"" + ancestorAttrValue + "\" and descendant::*[contains(.,\"" + ancestorEnclosedText + "\")]]]"); + StringBuilder xpathBuilder = new StringBuilder("//").append(element).append("[ancestor::*["); + + if (ancestorAttr != null) { + xpathBuilder.append("@").append(ancestorAttr).append("=\"").append(ancestorAttrValue) + .append("\" and preceding-sibling::*[descendant-or-self::*[contains(.,\"" + ancestorEnclosedText + "\")]]]") + .append(" or preceding-sibling::*[").append("@").append(ancestorAttr).append("=\"").append(ancestorAttrValue) + .append("\" and descendant-or-self::*[contains(.,\"" + ancestorEnclosedText + "\")]]]"); + } else { + xpathBuilder.append("preceding-sibling::*[descendant-or-self::*[contains(.,\"" + ancestorEnclosedText + "\")]]]]"); + } + + if (attr != null) { + xpathBuilder.append("[@").append(attr).append("=\"").append(attrValue).append("\"]"); + } + + return By.xpath(xpathBuilder.toString()); + } + + public static By byAncestorFollowingSiblingElementValue(String element, String attr, String attrValue, String ancestorAttr, String ancestorAttrValue, String ancestorEnclosedText) { + if (element == null) { + element = "*"; + } + + StringBuilder xpathBuilder = new StringBuilder("//").append(element).append("[ancestor::*["); + + if (ancestorAttr != null) { + xpathBuilder.append("@").append(ancestorAttr).append("=\"").append(ancestorAttrValue) + .append("\" and following-sibling::*[descendant-or-self::*[contains(.,\"" + ancestorEnclosedText + "\")]]]") + .append(" or following-sibling::*[").append("@").append(ancestorAttr).append("=\"").append(ancestorAttrValue) + .append("\" and descendant-or-self::*[contains(.,\"" + ancestorEnclosedText + "\")]]]"); + } else { + xpathBuilder.append("following-sibling::*[descendant-or-self::*[contains(.,\"" + ancestorEnclosedText + "\")]]]]"); + } + + if (attr != null) { + xpathBuilder.append("[@").append(attr).append("=\"").append(attrValue).append("\"]"); + } + + return By.xpath(xpathBuilder.toString()); } public static String qnameToString(QName qname) { diff --git a/tools/schrodinger/src/test/java/schrodinger/TestBase.java b/tools/schrodinger/src/test/java/schrodinger/TestBase.java index c5e14abeb50..f72958301c6 100644 --- a/tools/schrodinger/src/test/java/schrodinger/TestBase.java +++ b/tools/schrodinger/src/test/java/schrodinger/TestBase.java @@ -74,9 +74,15 @@ public void afterMethod(Method method) { LOG.info("Finished test {}.{}", method.getDeclaringClass().getName(), method.getName()); } - protected void importObject(File source) { + protected void importObject(File source,Boolean overrideExistingObject) { ImportObjectPage importPage = basicPage.importObject(); + + if(overrideExistingObject){ + importPage + .checkOverwriteExistingObject(); + } + Assert.assertTrue( importPage .getObjectsFromFile() @@ -85,4 +91,9 @@ protected void importObject(File source) { .feedback() .isSuccess()); } + + protected void importObject(File source) { + importObject(source,false); + } + } diff --git a/tools/schrodinger/src/test/java/schrodinger/scenarios/OrganizationStructureTests.java b/tools/schrodinger/src/test/java/schrodinger/scenarios/OrganizationStructureTests.java index 75dcd0cccd2..562883eeb66 100644 --- a/tools/schrodinger/src/test/java/schrodinger/scenarios/OrganizationStructureTests.java +++ b/tools/schrodinger/src/test/java/schrodinger/scenarios/OrganizationStructureTests.java @@ -25,12 +25,10 @@ public class OrganizationStructureTests extends TestBase { private static final File ORG_ACCOUNT_INDUCEMENT_FILE = new File("./src/test/resources/org-account-inducement.xml"); private static final File ORG_MONKEY_ISLAND_SOURCE_FILE = new File("../../samples/org/org-monkey-island-simple.xml"); - private static final File USER_TEST_RAPHAEL_FILE = new File("./src/test/resources/user-raphael.xml"); - - private static final String CSV_SOURCE_OLDVALUE = "target/midpoint.csv"; + protected static final File USER_TEST_RAPHAEL_FILE = new File("./src/test/resources/user-raphael.xml"); private static final String TEST_USER_GUYBRUSH_NAME = "guybrush"; - private static final String TEST_USER_RAPHAEL_NAME = "raphael"; + protected static final String TEST_USER_RAPHAEL_NAME = "raphael"; private static final String NAME_ORG_UNIT_ASSIGN= "P0001"; private static final String NAME_ORG_UNIT_UNASSIGN= "Save Elaine"; @@ -158,7 +156,7 @@ public void changeResourceFilePath(){ .clickByName("CSV (target with groups)") .clickEditResourceConfiguration() .form() - .changeAttributeValue("File path",CSV_SOURCE_OLDVALUE,CSV_TARGET_FILE.getAbsolutePath()) + .changeAttributeValue("File path",AccountTests.CSV_SOURCE_OLDVALUE, CSV_TARGET_FILE.getAbsolutePath()) .and() .and() .clickSaveAndTestConnection() diff --git a/tools/schrodinger/src/test/java/schrodinger/scenarios/PolyStringTests.java b/tools/schrodinger/src/test/java/schrodinger/scenarios/PolyStringTests.java index 2a30ea32aad..81cfe901fc2 100644 --- a/tools/schrodinger/src/test/java/schrodinger/scenarios/PolyStringTests.java +++ b/tools/schrodinger/src/test/java/schrodinger/scenarios/PolyStringTests.java @@ -19,6 +19,7 @@ public class PolyStringTests extends TestBase { private static final String TEST_USER_JOZKO_FULL_NAME = "Jožko Jörg Nguyễn Trißtan Guðmund Mrkvička"; private static final String TEST_USER_JOZKO_ADDITIONAL_NAME = "Jörg Nguyễn Trißtan Guðmund "; + private static final String CREATE_USER_WITH_DIACRITIC_DEPENDENCY = "createUserWithDiacritic"; @Test public void createUserWithDiacritic(){ UserPage user = basicPage.newUser(); @@ -40,7 +41,7 @@ public void createUserWithDiacritic(){ } - @Test + @Test (dependsOnMethods = {CREATE_USER_WITH_DIACRITIC_DEPENDENCY}) public void searchForUserWithDiacritic(){ ListUsersPage usersPage = basicPage.listUsers(); @@ -53,7 +54,9 @@ public void searchForUserWithDiacritic(){ .updateSearch() .and() .currentTableContains(TEST_USER_JOZKO_NAME) - ); + ); + + Assert.assertTrue( usersPage .table() .search() @@ -61,8 +64,8 @@ public void searchForUserWithDiacritic(){ .inputValue(TEST_USER_JOZKO_NAME_NO_DIAC) .updateSearch() .and() - .currentTableContains(TEST_USER_JOZKO_NAME_NO_DIAC); - + .currentTableContains(TEST_USER_JOZKO_NAME) + ); } } diff --git a/tools/schrodinger/src/test/java/schrodinger/scenarios/SynchronizationTests.java b/tools/schrodinger/src/test/java/schrodinger/scenarios/SynchronizationTests.java new file mode 100644 index 00000000000..bd098aedffa --- /dev/null +++ b/tools/schrodinger/src/test/java/schrodinger/scenarios/SynchronizationTests.java @@ -0,0 +1,219 @@ +package schrodinger.scenarios; + +import com.codeborne.selenide.Selenide; +import com.evolveum.midpoint.schrodinger.page.resource.ListResourcesPage; +import com.evolveum.midpoint.schrodinger.page.user.ListUsersPage; +import org.apache.commons.io.FileUtils; +import org.testng.Assert; +import org.testng.annotations.BeforeSuite; +import org.testng.annotations.Test; +import schrodinger.TestBase; + +import java.io.File; +import java.io.IOException; + +/** + * Created by matus on 5/21/2018. + */ +public class SynchronizationTests extends TestBase { + + private static final File CSV_SOURCE_FILE = new File("./src/test/resources/midpoint-gorups-authoritative.csv"); + private static final File CSV_INITIAL_SOURCE_FILE = new File("./src/test/resources/midpoint-gorups-authoritative-initial.csv"); + private static final File CSV_UPDATED_SOURCE_FILE = new File("./src/test/resources/midpoint-gorups-authoritative-updated.csv"); + private static final File CSV_TARGET_FILE = new File("C:\\Users\\matus\\Documents\\apache-tomcat-8.5.16\\target\\midpoint-advanced-sync.csv"); //TODO change hard coded path to local web container + private static final File RESOURCE_CSV_GROUPS_AUTHORITATIVE_FILE= new File("./src/test/resources/resource-csv-groups-authoritative.xml"); + + protected static final String TEST_USER_DON_NAME= "donatello"; + + private static final String RESOURCE_AND_SYNC_TASK_SETUP_DEPENDENCY = "setUpResourceAndSynchronizationTask"; + private static final String NEW_USER_AND_ACCOUNT_CREATED_DEPENDENCY = "newResourceAccountUserCreated"; + private static final String NEW_USER_ACCOUNT_CREATED_LINKED_DEPENDENCY = "newResourceAccountCreatedLinked"; + + @BeforeSuite + private void init() throws IOException { + FileUtils.copyFile(CSV_INITIAL_SOURCE_FILE,CSV_TARGET_FILE); + + } + + @Test + public void setUpResourceAndSynchronizationTask(){ + importObject(RESOURCE_CSV_GROUPS_AUTHORITATIVE_FILE,true); + importObject(OrganizationStructureTests.USER_TEST_RAPHAEL_FILE,true); + + ListResourcesPage listResourcesPage = basicPage.listResources(); + + Assert.assertTrue( + listResourcesPage + .table() + .clickByName("CSV (target with groups) authoritative") + .clickEditResourceConfiguration() + .form() + .changeAttributeValue("File path" ,AccountTests.CSV_SOURCE_OLDVALUE, CSV_TARGET_FILE.getAbsolutePath()) + .and() + .and() + .clickSaveAndTestConnection() + .isTestSuccess() + ); + + listResourcesPage = basicPage.listResources(); + listResourcesPage + .table() + .clickByName("CSV (target with groups) authoritative") + .clicAccountsTab() + .liveSyncTask() + .clickCreateNew() + .basicTable() + .addAttributeValue("Task name","LiveSyncTest") + .and() + .schedulingTable() + .clickCheckBox("Recurring task") + .addAttributeValue("Schedule interval (seconds)","3") + .and() + .clickSave() + .feedback() + .isSuccess(); + + } + + @Test (dependsOnMethods = {RESOURCE_AND_SYNC_TASK_SETUP_DEPENDENCY}) + public void newResourceAccountUserCreated() throws IOException { + FileUtils.copyFile(CSV_SOURCE_FILE,CSV_TARGET_FILE); + Selenide.sleep(3000); + + ListUsersPage usersPage = basicPage.listUsers(); + Assert.assertTrue( + usersPage + .table() + .search() + .byName() + .inputValue(TEST_USER_DON_NAME) + .updateSearch() + .and() + .currentTableContains(TEST_USER_DON_NAME) + ); + } + + @Test (dependsOnMethods = {NEW_USER_AND_ACCOUNT_CREATED_DEPENDENCY}) + public void newResourceAccountCreatedLinked() throws IOException { + + ListUsersPage usersPage = basicPage.listUsers(); + usersPage + .table() + .search() + .byName() + .inputValue(TEST_USER_DON_NAME) + .updateSearch() + .and() + .clickByName(TEST_USER_DON_NAME) + .selectTabProjections() + .table() + .selectCheckboxByName("CSV (target with groups) authoritative") + .and() + .clickCog() + .delete() + .clickYes() + .and() + .and() + .clickSave() + .feedback() + .isSuccess(); + + Selenide.sleep(3000); + FileUtils.copyFile(CSV_SOURCE_FILE,CSV_TARGET_FILE); + Selenide.sleep(3000); + + + usersPage = basicPage.listUsers(); + Assert.assertTrue( + usersPage + .table() + .search() + .byName() + .inputValue(TEST_USER_DON_NAME) + .updateSearch() + .and() + .clickByName(TEST_USER_DON_NAME) + .selectTabProjections() + .table() + .currentTableContains("CSV (target with groups) authoritative") + ); + + } + + @Test (dependsOnMethods = {NEW_USER_ACCOUNT_CREATED_LINKED_DEPENDENCY}) + public void alreadyLinkedResourceAccountModified() throws IOException { + + FileUtils.copyFile(CSV_UPDATED_SOURCE_FILE,CSV_TARGET_FILE); + Selenide.sleep(3000); + + ListUsersPage usersPage = basicPage.listUsers(); + Assert.assertTrue( + usersPage + .table() + .search() + .byName() + .inputValue(TEST_USER_DON_NAME) + .updateSearch() + .and() + .clickByName(TEST_USER_DON_NAME) + .selectTabBasic() + .form() + .compareAttibuteValue("Given name","Donato") + ); + } +//TODO checkbox selection not ideal rethink! + @Test (dependsOnMethods = {RESOURCE_AND_SYNC_TASK_SETUP_DEPENDENCY}) + public void resourceAccountDeleted(){ + + ListUsersPage usersPage = basicPage.listUsers(); + Assert.assertFalse( + usersPage + .table() + .search() + .byName() + .inputValue("raphael") + .updateSearch() + .and() + .clickByName("raphael") + .selectTabProjections() + .table() + .currentTableContains("CSV (target with groups) authoritative") + ); + + ListResourcesPage resourcesPage = basicPage.listResources(); + Assert.assertFalse( + resourcesPage + .table() + .search() + .byName() + .inputValue("CSV (target with groups) authoritative") + .updateSearch() + .and() + .clickByName("CSV (target with groups) authoritative") + .clicAccountsTab() + .clickSearchInResource() + .table() + .selectCheckboxByName("raphael") + .clickCog() + .clickDelete() + .clickYes() + .currentTableContains("raphael") + ); + + Assert.assertFalse( + usersPage + .table() + .search() + .byName() + .inputValue("raphael") + .updateSearch() + .and() + .clickByName("raphael") + .selectTabProjections() + .table() + .currentTableContains("CSV (target with groups) authoritative") + ); + + } + +} diff --git a/tools/schrodinger/src/test/resources/midpoint-gorups-authoritative-initial.csv b/tools/schrodinger/src/test/resources/midpoint-gorups-authoritative-initial.csv new file mode 100644 index 00000000000..acceec07652 --- /dev/null +++ b/tools/schrodinger/src/test/resources/midpoint-gorups-authoritative-initial.csv @@ -0,0 +1,3 @@ +"login","firstname","lastname","disabled","password","groups" +"admin","admin","admin",false,"","" +"raphael","Raffaello","Sanzio da Urbino","false","","" \ No newline at end of file diff --git a/tools/schrodinger/src/test/resources/midpoint-gorups-authoritative-updated.csv b/tools/schrodinger/src/test/resources/midpoint-gorups-authoritative-updated.csv new file mode 100644 index 00000000000..62310a937f9 --- /dev/null +++ b/tools/schrodinger/src/test/resources/midpoint-gorups-authoritative-updated.csv @@ -0,0 +1,4 @@ +"login","firstname","lastname","disabled","password","groups" +"admin","admin","admin",false,"","" +"raphael","Raffaello","Sanzio da Urbino","false","","" +"donatello","Donato","di Niccolo di Betto Bardi","false","","" \ No newline at end of file diff --git a/tools/schrodinger/src/test/resources/midpoint-gorups-authoritative.csv b/tools/schrodinger/src/test/resources/midpoint-gorups-authoritative.csv new file mode 100644 index 00000000000..dd3537d2020 --- /dev/null +++ b/tools/schrodinger/src/test/resources/midpoint-gorups-authoritative.csv @@ -0,0 +1,4 @@ +"login","firstname","lastname","disabled","password","groups" +"admin","admin","admin",false,"","" +"raphael","Raffaello","Sanzio da Urbino","false","","" +"donatello","Donatello","di Niccolo di Betto Bardi","false","","" diff --git a/tools/schrodinger/src/test/resources/resource-csv-groups-authoritative.xml b/tools/schrodinger/src/test/resources/resource-csv-groups-authoritative.xml new file mode 100644 index 00000000000..83c68629515 --- /dev/null +++ b/tools/schrodinger/src/test/resources/resource-csv-groups-authoritative.xml @@ -0,0 +1,216 @@ + + + + + + + + + CSV (target with groups) authoritative + CSV resource with "groups" attribute using single identifier (login) + + + + + c:connectorType + com.evolveum.polygon.connector.csv.CsvConnector + + + + + + + /var/tmp/midpoint-groups.csv + utf-8 + " + ALL + , + ; + login + password + + + + + + + + + + + + + Default Account + true + + ri:AccountObjectClass + + ri:login + + Login + + + 0 + + + + + $user/name + + + + + + ri:firstname + First name + Definition of Firstname attribute handling. + + + $user/givenName + + + + + ri:lastname + Last name + Definition of Lastname attribute handling. + + + $user/familyName + + + + + ri:groups + Groups + + + 0 + -1 + + + + + + + + + + + + + stringIgnoreCase + attributes/ri:login + admin + + + + + + + + + + + + + ri:disabled + false + true + + + + + + + + true + + + + Correlation expression is a search query. + Following search query will look for users that have "name" + equal to the "login" attribute of the account. Simply speaking, + it will look for match in usernames in the IDM and the resource. + The correlation rule always looks for users, so it will not match + any other object type. + + + c:name + + $account/attributes/ri:login + + + + + + + + + linked + true + + + deleted + true + + http://midpoint.evolveum.com/xml/ns/public/model/action-3#unlink + + + + unlinked + true + + http://midpoint.evolveum.com/xml/ns/public/model/action-3#link + + + + unmatched + true + + http://midpoint.evolveum.com/xml/ns/public/model/action-3#addFocus + + + + + \ No newline at end of file