diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/api/util/WebModelServiceUtils.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/api/util/WebModelServiceUtils.java index dba8e8b8b61..50430bc16cd 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/api/util/WebModelServiceUtils.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/api/util/WebModelServiceUtils.java @@ -26,11 +26,13 @@ import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.task.api.TaskManager; import com.evolveum.midpoint.util.exception.*; +import com.evolveum.midpoint.web.page.admin.PageAdminObjectDetails; import com.evolveum.midpoint.web.page.login.PageLogin; import com.evolveum.midpoint.web.security.MidPointApplication; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import com.evolveum.prism.xml.ns._public.types_3.EvaluationTimeType; +import org.apache.commons.lang.BooleanUtils; import org.apache.commons.lang.LocaleUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.Validate; @@ -711,4 +713,29 @@ public static void addIncludeOptionsForExportOrView(Collection getVisibleContainers() { - return Arrays.asList(ItemPath.EMPTY_PATH, new ItemPath(AbstractRoleType.F_DATA_PROTECTION), SchemaConstants.PATH_ACTIVATION, SchemaConstants.PATH_PASSWORD); + List paths = new ArrayList<>(); + paths.addAll(Arrays.asList(ItemPath.EMPTY_PATH, SchemaConstants.PATH_ACTIVATION, SchemaConstants.PATH_PASSWORD)); + if (WebModelServiceUtils.isEnableExperimentalFeature(getPageBase())) { + paths.add(new ItemPath(AbstractRoleType.F_DATA_PROTECTION)); + } + return paths; } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/objectdetails/FocusMainPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/objectdetails/FocusMainPanel.java index e6342e0f795..eef1f31caa9 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/objectdetails/FocusMainPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/objectdetails/FocusMainPanel.java @@ -303,40 +303,44 @@ public String getCount() { }); authorization = new FocusTabVisibleBehavior(unwrapModel(), ComponentConstants.UI_FOCUS_TAB_ASSIGNMENTS_URL); - tabs.add( - new CountablePanelTab(parentPage.createStringResource("pageAdminFocus.dataProtection"), authorization) { + + if (WebModelServiceUtils.isEnableExperimentalFeature(parentPage)) { + tabs.add(new CountablePanelTab(parentPage.createStringResource("pageAdminFocus.dataProtection"), authorization) { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; - @Override - public WebMarkupContainer createPanel(String panelId) { - return createFocusDataProtectionTabPanel(panelId, parentPage); - } + @Override + public WebMarkupContainer createPanel(String panelId) { + return createFocusDataProtectionTabPanel(panelId, parentPage); + } - @Override - public String getCount() { - PrismObject focus = getObjectModel().getObject().getObject(); - List assignments = focus.asObjectable().getAssignment(); - int count = 0; - for (AssignmentType assignment : assignments) { - if (assignment.getTargetRef() == null) { - continue; - } - if (QNameUtil.match(assignment.getTargetRef().getType(), OrgType.COMPLEX_TYPE)) { - Task task = parentPage.createSimpleTask("load data protection obejcts"); - PrismObject org = WebModelServiceUtils.loadObject(assignment.getTargetRef(), parentPage, task, task.getResult()); - - if (org != null) { - if (org.asObjectable().getOrgType().contains("access")) { - count++; - } + @Override + public String getCount() { + PrismObject focus = getObjectModel().getObject().getObject(); + List assignments = focus.asObjectable().getAssignment(); + int count = 0; + for (AssignmentType assignment : assignments) { + if (assignment.getTargetRef() == null) { + continue; + } + if (QNameUtil.match(assignment.getTargetRef().getType(), OrgType.COMPLEX_TYPE)) { + Task task = parentPage.createSimpleTask("load data protection obejcts"); + PrismObject org = WebModelServiceUtils.loadObject(assignment.getTargetRef(), parentPage, + task, task.getResult()); + + if (org != null) { + if (org.asObjectable().getOrgType().contains("access")) { + count++; } } } - - return String.valueOf(count); } - }); + + return String.valueOf(count); + } + }); + } + authorization = new FocusTabVisibleBehavior(unwrapModel(), ComponentConstants.UI_FOCUS_TAB_TASKS_URL); tabs.add( diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/PrismPropertyPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/PrismPropertyPanel.java index 45143df91ff..ca259899006 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/PrismPropertyPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/PrismPropertyPanel.java @@ -19,6 +19,7 @@ import com.evolveum.midpoint.common.refinery.RefinedAttributeDefinition; import com.evolveum.midpoint.gui.api.model.LoadableModel; import com.evolveum.midpoint.gui.api.page.PageBase; +import com.evolveum.midpoint.gui.api.util.WebComponentUtil; import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.prism.path.ItemPath; diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/InternalsCachePanel.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/InternalsCachePanel.html new file mode 100644 index 00000000000..5836f543337 --- /dev/null +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/InternalsCachePanel.html @@ -0,0 +1,33 @@ + + + + + + +
+
+

+ +
+ +
+ +
+
+
+ + \ No newline at end of file diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/InternalsCachePanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/InternalsCachePanel.java new file mode 100644 index 00000000000..e68688451aa --- /dev/null +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/InternalsCachePanel.java @@ -0,0 +1,36 @@ +package com.evolveum.midpoint.web.page.admin.configuration; + +import org.apache.wicket.ajax.AjaxRequestTarget; + +import com.evolveum.midpoint.gui.api.component.BasePanel; +import com.evolveum.midpoint.web.component.AjaxButton; + +public class InternalsCachePanel extends BasePanel{ + + private static final long serialVersionUID = 1L; + + private static final String ID_CLEAR_CACHES_BUTTON = "clearCaches"; + + public InternalsCachePanel(String id) { + super(id); + } + + @Override + protected void onInitialize() { + super.onInitialize(); + + AjaxButton clearCustomFunctionCache = new AjaxButton(ID_CLEAR_CACHES_BUTTON, createStringResource("InternalsCachePanel.button.clearCaches")) { + + private static final long serialVersionUID = 1L; + + @Override + public void onClick(AjaxRequestTarget target) { + getPageBase().getModelInteractionService().clearCaches(); + } + }; + + add(clearCustomFunctionCache); + } + + +} diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageInternals.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageInternals.java index ffd1d36b3a6..34e1856371d 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageInternals.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageInternals.java @@ -135,6 +135,16 @@ public WebMarkupContainer getPanel(String panelId) { } }); + tabs.add(new AbstractTab(createStringResource("PageInternals.tab.cache")) { + + private static final long serialVersionUID = 1L; + + @Override + public WebMarkupContainer getPanel(String panelId) { + return initCachePanel(panelId); + } + }); + TabbedPanel tabPannel = new TabbedPanel<>(ID_TAB_PANEL, tabs); add(tabPannel); @@ -157,7 +167,11 @@ private WebMarkupContainer initTraces(String panelId) { } private WebMarkupContainer initCounters(String panelId) { - return new InternalsCountersPanel(panelId); + return new InternalsCountersPanel(panelId); + } + + private WebMarkupContainer initCachePanel(String panelId) { + return new InternalsCachePanel(panelId); } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/MidPointAccessDeniedHandler.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/MidPointAccessDeniedHandler.java index efa1c7ac326..266d91c058c 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/MidPointAccessDeniedHandler.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/MidPointAccessDeniedHandler.java @@ -16,11 +16,13 @@ package com.evolveum.midpoint.web.security; +import org.apache.commons.lang.StringUtils; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.web.access.AccessDeniedHandler; import org.springframework.security.web.access.AccessDeniedHandlerImpl; import org.springframework.security.web.csrf.MissingCsrfTokenException; +import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -55,6 +57,20 @@ private boolean isLoginLogoutRequest(HttpServletRequest req) { } String uri = req.getRequestURI(); - return "/j_spring_security_logout".equals(uri) || "/spring_security_login".equals(uri); + return createUri(req, "/j_spring_security_logout").equals(uri) + || createUri(req, "/spring_security_login").equals(uri); + } + + private String createUri(HttpServletRequest req, String uri) { + StringBuilder sb = new StringBuilder(); + + ServletContext ctx = req.getServletContext(); + String ctxPath = ctx.getContextPath(); + if (StringUtils.isNotEmpty(ctxPath)) { + sb.append(ctxPath); + } + sb.append(uri); + + return sb.toString(); } } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/MidPointApplication.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/MidPointApplication.java index f9aab29f3ac..e9fd4420b30 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/MidPointApplication.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/MidPointApplication.java @@ -19,6 +19,7 @@ import com.evolveum.midpoint.common.LocalizationService; import com.evolveum.midpoint.common.configuration.api.MidpointConfiguration; import com.evolveum.midpoint.gui.api.page.PageBase; +import com.evolveum.midpoint.gui.api.util.MidPointApplicationConfiguration; import com.evolveum.midpoint.gui.api.util.WebComponentUtil; import com.evolveum.midpoint.gui.api.util.WebModelServiceUtils; import com.evolveum.midpoint.model.api.*; @@ -279,6 +280,12 @@ public void updateAjaxAttributes(AbstractDefaultAjaxBehavior behavior, AjaxReque //descriptor loader, used for customization new DescriptorLoader().loadData(this); + Map map = + applicationContext.getBeansOfType(MidPointApplicationConfiguration.class); + if (map != null) { + map.forEach((key, value) -> value.init(this)); + } + // for schrodinger selenide library initializeSchrodinger(); } diff --git a/gui/admin-gui/src/main/resources/localization/Midpoint.properties b/gui/admin-gui/src/main/resources/localization/Midpoint.properties index 27133dc1f14..6ccea3eefe0 100755 --- a/gui/admin-gui/src/main/resources/localization/Midpoint.properties +++ b/gui/admin-gui/src/main/resources/localization/Midpoint.properties @@ -3939,3 +3939,6 @@ CertCampaignStateFilter.REVIEW_STAGE_DONE=Review stage done CertCampaignStateFilter.IN_REMEDIATION=In remediation CertCampaignStateFilter.CLOSED=Closed pageAdminFocus.dataProtection=Data protection +PageInternals.title.cache=Caches +PageInternals.tab.cache=Cache management +InternalsCachePanel.button.clearCaches=Clear caches diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/internals/InternalCounters.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/internals/InternalCounters.java index 0f56315d6f1..d1549bdadbf 100644 --- a/infra/schema/src/main/java/com/evolveum/midpoint/schema/internals/InternalCounters.java +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/internals/InternalCounters.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2017 Evolveum + * Copyright (c) 2017-2018 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,7 +24,9 @@ public enum InternalCounters { RESOURCE_SCHEMA_FETCH_COUNT("resourceSchemaFetchCount", "resource schema fetch count", InternalOperationClasses.REPOSITORY_OPERATIONS), - RESOURCE_REPOSITORY_READ_COUNT("resourceRepositoryReadCount", "resource repository read count", null), + RESOURCE_REPOSITORY_READ_COUNT("resourceRepositoryReadCount", "resource repository read count", InternalOperationClasses.REPOSITORY_OPERATIONS), + + RESOURCE_REPOSITORY_MODIFY_COUNT("resourceRepositoryModifyCount", "resource repository modify count", InternalOperationClasses.REPOSITORY_OPERATIONS), CONNECTOR_INSTANCE_INITIALIZATION_COUNT("connectorInstanceInitializationCount", "connector instance initialization count", InternalOperationClasses.CONNECTOR_OPERATIONS), diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/internals/InternalMonitor.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/internals/InternalMonitor.java index 5c2e1c206c4..8fe6ee11d9f 100644 --- a/infra/schema/src/main/java/com/evolveum/midpoint/schema/internals/InternalMonitor.java +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/internals/InternalMonitor.java @@ -65,7 +65,7 @@ public static void recordCount(InternalCounters counter) { long count = recordCountInternal(counter); InternalOperationClasses operationClass = counter.getOperationClass(); if (operationClass != null && isTrace(operationClass)) { - traceOperation(operationClass, count); + traceOperation(counter, operationClass, count); } } @@ -100,12 +100,12 @@ public static void setTrace(InternalOperationClasses operationClass, boolean val traceMap.put(operationClass, val); } - private static void traceOperation(InternalOperationClasses operationClass, long counter) { - traceOperation(operationClass.getKey(), null, counter, false); + private static void traceOperation(InternalCounters counter, InternalOperationClasses operationClass, long count) { + traceOperation(counter.getKey() + "["+ operationClass.getKey() +"]", null, count, false); } - private static void traceOperation(String opName, Supplier paramsSupplier, long counter, boolean traceAndDebug) { - LOGGER.info("MONITOR {} ({})", opName, counter); + private static void traceOperation(String opName, Supplier paramsSupplier, long count, boolean traceAndDebug) { + LOGGER.info("MONITOR {} ({})", opName, count); if (LOGGER.isDebugEnabled()) { StackTraceElement[] fullStack = Thread.currentThread().getStackTrace(); String immediateClass = null; @@ -129,9 +129,9 @@ private static void traceOperation(String opName, Supplier paramsSupplie params = paramsSupplier.get(); } if (traceAndDebug) { - LOGGER.debug("MONITOR {}({}) ({}): {} {}", opName, params, counter, immediateClass, immediateMethod); + LOGGER.debug("MONITOR {}({}) ({}): {} {}", opName, params, count, immediateClass, immediateMethod); } - LOGGER.trace("MONITOR {}({}) ({}):\n{}", opName, params, counter, sb); + LOGGER.trace("MONITOR {}({}) ({}):\n{}", opName, params, count, sb); } } diff --git a/infra/schema/src/main/resources/xml/ns/public/common/api-types-3.xsd b/infra/schema/src/main/resources/xml/ns/public/common/api-types-3.xsd index e4735310eba..5428d4e7efe 100644 --- a/infra/schema/src/main/resources/xml/ns/public/common/api-types-3.xsd +++ b/infra/schema/src/main/resources/xml/ns/public/common/api-types-3.xsd @@ -544,7 +544,7 @@ - + diff --git a/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd b/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd index 4c5e0cecb21..3ec743e876a 100755 --- a/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd +++ b/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd @@ -14589,16 +14589,57 @@ + + + - + + + + TODO + + + + + + + + + + + + + + + TODO + + + + + + + + + + + + + + + + + + + + @@ -18776,6 +18817,7 @@ Literal value. + diff --git a/infra/schema/src/test/java/com/evolveum/midpoint/schema/TestSerialization.java b/infra/schema/src/test/java/com/evolveum/midpoint/schema/TestSerialization.java index 4d8e840a508..eac0d65a98c 100644 --- a/infra/schema/src/test/java/com/evolveum/midpoint/schema/TestSerialization.java +++ b/infra/schema/src/test/java/com/evolveum/midpoint/schema/TestSerialization.java @@ -21,16 +21,20 @@ import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.prism.util.PrismTestUtil; import com.evolveum.midpoint.schema.constants.MidPointConstants; +import com.evolveum.midpoint.schema.util.LocalizationUtil; import com.evolveum.midpoint.util.MiscUtil; import com.evolveum.midpoint.util.PrettyPrinter; import com.evolveum.midpoint.util.SerializationUtil; +import com.evolveum.midpoint.util.SingleLocalizableMessage; import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.xml.ns._public.common.api_types_3.ExecuteCredentialResetResponseType; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import org.testng.annotations.BeforeSuite; import org.testng.annotations.Test; import org.xml.sax.SAXException; +import javax.xml.namespace.QName; import java.io.File; import java.io.IOException; import java.util.List; @@ -42,14 +46,41 @@ */ public class TestSerialization { - - @BeforeSuite public void setup() throws SchemaException, SAXException, IOException { PrettyPrinter.setDefaultNamespacePrefix(MidPointConstants.NS_MIDPOINT_PUBLIC_PREFIX); PrismTestUtil.resetPrismContext(MidPointPrismContextFactory.FACTORY); } + @Test + public void testSerializeMessage() throws Exception { + System.out.println("===[ testSerializeMessage ]==="); + + PrismContext prismContext = PrismTestUtil.getPrismContext(); + SingleLocalizableMessage localizableMessage = new SingleLocalizableMessage("execute.reset.credential.bad.request", null, "Failed to execute reset password. Bad request."); + LocalizableMessageType localizableMessageBean = LocalizationUtil.createLocalizableMessageType(localizableMessage); + QName fakeQName = new QName(PrismConstants.NS_TYPES, "object"); + String xml = prismContext.xmlSerializer().serializeAnyData(localizableMessageBean, fakeQName); + System.out.println(xml); + } + + @Test + public void testSerializeExecuteCredentialResetResponseType() throws Exception { + System.out.println("===[ testSerializeExecuteCredentialResetResponseType ]==="); + + PrismContext prismContext = PrismTestUtil.getPrismContext(); + + SingleLocalizableMessage localizableMessage = new SingleLocalizableMessage("execute.reset.credential.bad.request", null, "Failed to execute reset password. Bad request."); + LocalizableMessageType localizableMessageBean = LocalizationUtil.createLocalizableMessageType(localizableMessage); + ExecuteCredentialResetResponseType response = new ExecuteCredentialResetResponseType(); + response.setMessage(localizableMessageBean); + QName fakeQName = new QName(PrismConstants.NS_TYPES, "object"); + + prismContext.adopt(response); + + String xml = prismContext.xmlSerializer().serializeAnyData(response, fakeQName); + System.out.println(xml); + } @Test public void testSerializeResource() throws Exception { diff --git a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelInteractionService.java b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelInteractionService.java index 13bcd333789..9bb57678ffe 100644 --- a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelInteractionService.java +++ b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelInteractionService.java @@ -333,4 +333,6 @@ public ExecuteCredentialResetResponseType executeCredentialsReset(PrismObject customFunctionLibraryCache; + private CacheRegistry cahceRegistry; + + @PostConstruct + public void register() { + cahceRegistry.registerCacheableService(this); + } + public ScriptExpressionFactory(PrismContext prismContext, Protector protector, RepositoryService repositoryService) { this.prismContext = prismContext; this.protector = protector; @@ -89,6 +100,14 @@ public void setFunctions(Collection functions) { public Map getEvaluators() { return evaluatorMap; } + + public CacheRegistry geCachetRegistry() { + return cahceRegistry; + } + + public void setCacheRegistry(CacheRegistry registry) { + this.cahceRegistry = registry; + } public ScriptExpression createScriptExpression(ScriptExpressionEvaluatorType expressionType, ItemDefinition outputDefinition, ExpressionFactory expressionFactory, String shortDesc, Task task, OperationResult result) throws ExpressionSyntaxException { @@ -161,5 +180,9 @@ private String getLanguage(ScriptExpressionEvaluatorType expressionType) { return DEFAULT_LANGUAGE; } + @Override + public void clearCache() { + customFunctionLibraryCache = null; + } } diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/stringpolicy/StringPolicyUtils.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/stringpolicy/StringPolicyUtils.java index ef5fd1e6bc0..53223913494 100644 --- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/stringpolicy/StringPolicyUtils.java +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/stringpolicy/StringPolicyUtils.java @@ -50,7 +50,7 @@ public static StringPolicyType normalize(StringPolicyType sp) { LimitationsType sl = new LimitationsType(); sl.setCheckAgainstDictionary(false); sl.setCheckPattern(""); - sl.setMaxLength(-1); + sl.setMaxLength(Integer.MAX_VALUE); sl.setMinLength(0); sl.setMinUniqueChars(0); sp.setLimitations(sl); diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/stringpolicy/ValuePolicyProcessor.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/stringpolicy/ValuePolicyProcessor.java index d63fdba87c7..295de4eb177 100644 --- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/stringpolicy/ValuePolicyProcessor.java +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/stringpolicy/ValuePolicyProcessor.java @@ -172,6 +172,7 @@ public boolean validateValue(String newValue, ValuePolicy AbstractValuePolicyOriginResolver originResolver, List messages, String shortDesc, Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException, SecurityViolationException { + //TODO: do we want to throw exception when no value policy defined?? Validate.notNull(pp, "Value policy must not be null."); OperationResult result = parentResult.createSubresult(OPERATION_STRING_POLICY_VALIDATION); diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/ModelRestService.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/ModelRestService.java index d996830bb5e..5a6a6baa73b 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/ModelRestService.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/ModelRestService.java @@ -108,6 +108,7 @@ public class ModelRestService { public static final String OPERATION_VALIDATE_VALUE_RPC = CLASS_DOT + "validateValueRpc"; public static final String OPERATION_GENERATE_VALUE = CLASS_DOT + "generateValue"; public static final String OPERATION_GENERATE_VALUE_RPC = CLASS_DOT + "generateValueRpc"; + public static final String OPERATION_EXECUTE_CREDENTIAL_RESET = CLASS_DOT + "executeCredentialReset"; private static final String CURRENT = "current"; private static final String VALIDATE = "validate"; @@ -1040,7 +1041,7 @@ public Response getLog(@QueryParam("fromPosition") Long fromPosition, @QueryPara @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, "application/yaml"}) public Response executeCredentialReset(@PathParam("oid") String oid, ExecuteCredentialResetRequestType executeCredentialResetRequest, @Context MessageContext mc) { Task task = RestServiceUtil.initRequest(mc); - OperationResult result = task.getResult().createSubresult(OPERATION_GET_LOG_FILE_CONTENT); + OperationResult result = task.getResult().createSubresult(OPERATION_EXECUTE_CREDENTIAL_RESET); Response response; try { diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java index 2eaba84408a..7118ce507b1 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java @@ -50,6 +50,8 @@ import com.evolveum.midpoint.repo.api.RepoAddOptions; import com.evolveum.midpoint.repo.api.RepositoryService; import com.evolveum.midpoint.repo.cache.RepositoryCache; +import com.evolveum.midpoint.repo.common.CacheRegistry; +import com.evolveum.midpoint.repo.common.Cacheable; import com.evolveum.midpoint.schema.*; import com.evolveum.midpoint.schema.constants.ObjectTypes; import com.evolveum.midpoint.schema.internals.InternalsConfig; @@ -147,6 +149,7 @@ public class ModelController implements ModelService, TaskService, WorkflowServi @Autowired private ObjectMerger objectMerger; @Autowired private SystemObjectCache systemObjectCache; @Autowired private EmulatedSearchProvider emulatedSearchProvider; + @Autowired private CacheRegistry cacheRegistry; @Autowired(required = true) @Qualifier("cacheRepositoryService") @@ -402,7 +405,7 @@ public Collection> executeChanges(fin result1.muteLastSubresultError(); } } - + final boolean preAuthorized = ModelExecuteOptions.isPreAuthorized(options); PrismObject objectToDetermineDetailsForAudit = null; try { @@ -610,6 +613,11 @@ private void invalidateCaches(Collection boolean validateValue(PrismObject object, V ValuePolicyType stringPolicy = resolveValuePolicy(policyItemDefinition, policy, task, parentResult); - RawType rawValue = (RawType) policyItemDefinition.getValue(); + Object value = policyItemDefinition.getValue(); String valueToValidate = null; - + if (value instanceof RawType) { + valueToValidate = ((RawType) value).getParsedRealValue(String.class); + } else { + valueToValidate = (String) value; + } + List valuesToValidate = new ArrayList<>(); PolicyItemTargetType target = policyItemDefinition.getTarget(); ItemPath path = null; if (target != null) { path = target.getPath().getItemPath(); } - if (rawValue != null) { - valueToValidate = rawValue.getParsedRealValue(String.class); + if (StringUtils.isNotEmpty(valueToValidate)) { valuesToValidate.add(valueToValidate); } else { if (target == null || target.getPath() == null) { @@ -1225,6 +1315,10 @@ private boolean validateValue(PrismObject object, V OperationResult result = parentResult.createSubresult(OPERATION_VALIDATE_VALUE + ".value"); if (path != null ) result.addArbitraryObjectAsParam("path", path); result.addParam("valueToValidate", newValue); + if (stringPolicy == null) { + stringPolicy = new ValuePolicyType(); + stringPolicy.setName(PolyString.toPolyStringType(new PolyString("Default policy"))); + } if (!policyProcessor.validateValue(newValue, stringPolicy, createOriginResolver(object, result), "validate value " + (path!= null ? "for " + path : "") + " for " + object + " value " + valueToValidate, task, result)) { result.recordFatalError("Validation for value " + newValue + " against policy " + stringPolicy + " failed"); LOGGER.error("Validation for value {} against policy {} failed", newValue, stringPolicy); @@ -1479,13 +1573,13 @@ public ExecuteCredentialResetResponseType executeCredentialsReset(PrismObject passwordObjectDelta = ObjectDelta.createModificationReplaceProperty(UserType.class, user.getOid(), - SchemaConstants.PATH_PASSWORD_VALUE, prismContext, newProtectedPassword); + + CredentialSourceType credentialSourceType = resetPolicyType.getNewCredentialSource(); + + if (credentialSourceType == null) { + //TODO: go through deprecated functionality + LocalizableMessage localizableMessage = builder.fallbackMessage("Failed to execute reset password. No credential source.").key("execute.reset.credential.no.credential.source").build(); + response = response.message(LocalizationUtil.createLocalizableMessageType(localizableMessage)); + //for now just let the user know that he needs to specify it + return response; + } + + ValuePolicyType valuePolicy = getValuePolicy(user, task, parentResult); + + ObjectDelta userDelta = null; + if (credentialSourceType.getUserEntry() != null) { + PolicyItemDefinitionType policyItemDefinitione = new PolicyItemDefinitionType(); + policyItemDefinitione.setValue(executeCredentialResetRequest.getUserEntry()); + + if (!validateValue(user, valuePolicy, policyItemDefinitione, task, parentResult)) { + LOGGER.error("Cannot execute reset password. New password doesn't satisfy policy constraints"); + parentResult.recordFatalError("Cannot execute reset password. New password doesn't satisfy policy constraints"); + LocalizableMessage localizableMessage = builder.fallbackMessage("New password doesn't satisfy policy constraints.").key("execute.reset.credential.validation.failed").build(); + throw new PolicyViolationException(localizableMessage); + } + + ProtectedStringType newProtectedPassword = new ProtectedStringType(); + newProtectedPassword.setClearValue(executeCredentialResetRequest.getUserEntry()); + userDelta = ObjectDelta.createModificationReplaceProperty(UserType.class, user.getOid(), + SchemaConstants.PATH_PASSWORD_VALUE, prismContext, newProtectedPassword); + } + if (BooleanUtils.isTrue(resetPolicyType.isForceChange())) { - passwordObjectDelta.addModificationReplaceProperty(SchemaConstants.PATH_PASSWORD_FORCE_CHANGE, Boolean.TRUE); + if (userDelta != null) { + userDelta.addModificationReplaceProperty(SchemaConstants.PATH_PASSWORD_FORCE_CHANGE, Boolean.TRUE); + } } + try { Collection> result = modelService.executeChanges( - MiscUtil.createCollection(passwordObjectDelta), ModelExecuteOptions.createRaw(), task, parentResult); + MiscUtil.createCollection(userDelta), ModelExecuteOptions.createRaw(), task, parentResult); } catch (ObjectNotFoundException | SchemaException | CommunicationException | ConfigurationException | SecurityViolationException | ExpressionEvaluationException | ObjectAlreadyExistsException | PolicyViolationException e) { -// SingleLocalizableMessage localizableMessage = new SingleLocalizableMessage("execute.reset.credential.failed", null, "Failed to execute reset password. Bad method."); -// response = response.message(LocalizationUtil.createLocalizableMessageType(localizableMessage)); response.message(LocalizationUtil.createForFallbackMessage("Failed to reset credential: " + e.getMessage())); throw e; } parentResult.recomputeStatus(); - LocalizableMessage message = new SingleLocalizableMessage("execute.reset.credential.successful", null, "Reset password was successful"); + LocalizableMessage message = builder.fallbackMessage("Reset password was successful").key("execute.reset.credential.successful").fallbackLocalizableMessage(null).build(); response.setMessage(LocalizationUtil.createLocalizableMessageType(message)); return response; } + public void clearCaches() { + cacheRegistry.clearAllCaches(); + } } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/sync/FocusValidityScannerTaskHandler.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/sync/FocusValidityScannerTaskHandler.java index 451e222932a..5376d77881d 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/sync/FocusValidityScannerTaskHandler.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/sync/FocusValidityScannerTaskHandler.java @@ -91,7 +91,7 @@ public class FocusValidityScannerTaskHandler extends AbstractScannerTaskHandler< private synchronized void initProcessedOids(Task coordinatorTask) { Validate.notNull(coordinatorTask.getOid(), "Task OID is null"); - processedOidsMap.put(coordinatorTask.getOid(), new HashSet()); + processedOidsMap.put(coordinatorTask.getOid(), new HashSet<>()); } // TODO fix possible (although very small) memory leak occurring when task finishes unsuccessfully @@ -129,9 +129,9 @@ protected Class getType(Task task) { protected ObjectQuery createQuery(AbstractScannerResultHandler handler, TaskRunResult runResult, Task coordinatorTask, OperationResult opResult) throws SchemaException { initProcessedOids(coordinatorTask); - TimeValidityPolicyConstraintType validtyContraintType = getValidityPolicyConstraint(coordinatorTask); + TimeValidityPolicyConstraintType validityConstraintType = getValidityPolicyConstraint(coordinatorTask); - Duration activateOn = getActivateOn(validtyContraintType); + Duration activateOn = getActivateOn(validityConstraintType); ObjectQuery query = new ObjectQuery(); ObjectFilter filter; @@ -140,7 +140,7 @@ protected ObjectQuery createQuery(AbstractScannerResultHandler handle XMLGregorianCalendar lastScanTimestamp = handler.getLastScanTimestamp(); XMLGregorianCalendar thisScanTimestamp = handler.getThisScanTimestamp(); if (activateOn != null) { - ItemPathType itemPathType = validtyContraintType.getItem(); + ItemPathType itemPathType = validityConstraintType.getItem(); ItemPath path = itemPathType.getItemPath(); if (path == null) { throw new SchemaException("No path defined in the validity constraint."); @@ -161,14 +161,12 @@ protected ObjectQuery createQuery(AbstractScannerResultHandler handle return query; } - private Duration getActivateOn(TimeValidityPolicyConstraintType validtyContraintType) { - - Duration activateOn = null; - if (validtyContraintType != null) { - activateOn = validtyContraintType.getActivateOn(); + private Duration getActivateOn(TimeValidityPolicyConstraintType validityConstraintType) { + if (validityConstraintType != null) { + return validityConstraintType.getActivateOn(); + } else { + return null; } - - return activateOn; } private ObjectFilter createBasicFilter(XMLGregorianCalendar lastScanTimestamp, XMLGregorianCalendar thisScanTimestamp){ @@ -217,9 +215,9 @@ private ObjectFilter createFilterFor(Class type, ItemPath path, XMLGregorianCale @Override protected void finish(AbstractScannerResultHandler handler, TaskRunResult runResult, Task coordinatorTask, OperationResult opResult) throws SchemaException { - TimeValidityPolicyConstraintType validtyContraintType = getValidityPolicyConstraint(coordinatorTask); + TimeValidityPolicyConstraintType validityConstraintType = getValidityPolicyConstraint(coordinatorTask); - Duration activateOn = getActivateOn(validtyContraintType); + Duration activateOn = getActivateOn(validityConstraintType); if (activateOn != null) { handler.getThisScanTimestamp().add(activateOn); } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/trigger/TriggerScannerTaskHandler.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/trigger/TriggerScannerTaskHandler.java index 6d244359744..e789b44ab2f 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/trigger/TriggerScannerTaskHandler.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/trigger/TriggerScannerTaskHandler.java @@ -169,9 +169,7 @@ protected boolean handleObject(PrismObject object, Task workerTask, } private void fireTriggers(AbstractScannerResultHandler handler, PrismObject object, Task workerTask, Task coordinatorTask, - OperationResult result) throws SchemaException, - ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ObjectAlreadyExistsException, - ConfigurationException, PolicyViolationException, SecurityViolationException { + OperationResult result) { PrismContainer triggerContainer = object.findContainer(F_TRIGGER); if (triggerContainer == null) { LOGGER.warn("Strange thing, attempt to fire triggers on {}, but it does not have trigger container", object); diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/util/AbstractScannerTaskHandler.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/util/AbstractScannerTaskHandler.java index bfd5166bd45..c3435ec0178 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/util/AbstractScannerTaskHandler.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/util/AbstractScannerTaskHandler.java @@ -50,8 +50,7 @@ public abstract class AbstractScannerTaskHandler> extends AbstractSearchIterativeModelTaskHandler { - @Autowired(required = true) - protected Clock clock; + @Autowired protected Clock clock; private static final transient Trace LOGGER = TraceManager.getTrace(AbstractScannerTaskHandler.class); @@ -64,7 +63,7 @@ protected boolean initializeRun(H handler, TaskRunResult runResult, Task task, OperationResult opResult) { boolean cont = super.initializeRun(handler, runResult, task, opResult); if (!cont) { - return cont; + return false; } XMLGregorianCalendar lastScanTimestamp = null; @@ -83,13 +82,25 @@ protected boolean initializeRun(H handler, TaskRunResult runResult, protected void finish(H handler, TaskRunResult runResult, Task task, OperationResult opResult) throws SchemaException { super.finish(handler, runResult, task, opResult); - PrismPropertyDefinition lastScanTimestampDef = new PrismPropertyDefinitionImpl<>( - SchemaConstants.MODEL_EXTENSION_LAST_SCAN_TIMESTAMP_PROPERTY_NAME, - DOMUtil.XSD_DATETIME, prismContext); - PropertyDelta lastScanTimestampDelta = new PropertyDelta( - new ItemPath(TaskType.F_EXTENSION, SchemaConstants.MODEL_EXTENSION_LAST_SCAN_TIMESTAMP_PROPERTY_NAME), lastScanTimestampDef, prismContext); - lastScanTimestampDelta.setValueToReplace(new PrismPropertyValue(handler.getThisScanTimestamp())); - task.modifyExtension(lastScanTimestampDelta); + if (task.canRun()) { + /* + * We want to update last scan timestamp only if the task has finished its current duties. + * Otherwise we might skip e.g. some triggers or validity boundaries - those that the task + * has not reached yet. They would be left unprocessed forever. See MID-4474. + * + * Note this is not the whole solution. It is necessary to review AbstractSearchIterativeResultHandler.handle() + * and shouldStop() methods and use 'stop' flag at this place as well. Hopefully such stopping is (very probably) + * not requested by any scanner task handlers. + */ + PrismPropertyDefinition lastScanTimestampDef = new PrismPropertyDefinitionImpl<>( + SchemaConstants.MODEL_EXTENSION_LAST_SCAN_TIMESTAMP_PROPERTY_NAME, + DOMUtil.XSD_DATETIME, prismContext); + PropertyDelta lastScanTimestampDelta = new PropertyDelta<>( + new ItemPath(TaskType.F_EXTENSION, SchemaConstants.MODEL_EXTENSION_LAST_SCAN_TIMESTAMP_PROPERTY_NAME), + lastScanTimestampDef, prismContext); + lastScanTimestampDelta.setValueToReplace(new PrismPropertyValue<>(handler.getThisScanTimestamp())); + task.modifyExtension(lastScanTimestampDelta); + } } @Override diff --git a/model/model-impl/src/main/resources/ctx-model.xml b/model/model-impl/src/main/resources/ctx-model.xml index 70993092483..4e5cdac0b2e 100644 --- a/model/model-impl/src/main/resources/ctx-model.xml +++ b/model/model-impl/src/main/resources/ctx-model.xml @@ -131,7 +131,8 @@ - + + @@ -216,6 +217,7 @@ + task = getTask(taskOid); display("Task", task); - PrismContainer taskExtension = task.getExtension(); - assertNotNull("No task extension", taskExtension); - PrismProperty lastRecomputeTimestampProp = taskExtension.findProperty(SchemaConstants.MODEL_EXTENSION_LAST_SCAN_TIMESTAMP_PROPERTY_NAME); - assertNotNull("no lastRecomputeTimestamp property", lastRecomputeTimestampProp); - XMLGregorianCalendar lastRecomputeTimestamp = lastRecomputeTimestampProp.getRealValue(); - assertNotNull("null lastRecomputeTimestamp", lastRecomputeTimestamp); - TestUtil.assertBetween("lastRecomputeTimestamp", startCal, endCal, lastRecomputeTimestamp); + PrismContainer taskExtension = task.getExtension(); + assertNotNull("No task extension", taskExtension); + PrismProperty lastScanTimestampProp = taskExtension.findProperty(SchemaConstants.MODEL_EXTENSION_LAST_SCAN_TIMESTAMP_PROPERTY_NAME); + assertNotNull("no lastScanTimestamp property", lastScanTimestampProp); + return lastScanTimestampProp.getRealValue(); } - protected void assertPasswordMetadata(PrismObject user, boolean create, XMLGregorianCalendar start, XMLGregorianCalendar end) { + protected void assertPasswordMetadata(PrismObject user, boolean create, XMLGregorianCalendar start, XMLGregorianCalendar end) { assertPasswordMetadata(user, create, start, end, USER_ADMINISTRATOR_OID, SchemaConstants.CHANNEL_GUI_USER_URI); } diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestDeputy.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestDeputy.java index 61d695a8c30..88a54290219 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestDeputy.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestDeputy.java @@ -1271,7 +1271,7 @@ public void test800ImportValidityScannerTask() throws Exception { // THEN displayThen(TEST_NAME); XMLGregorianCalendar endCal = clock.currentTimeXMLGregorianCalendar(); - assertLastRecomputeTimestamp(TASK_VALIDITY_SCANNER_OID, startCal, endCal); + assertLastScanTimestamp(TASK_VALIDITY_SCANNER_OID, startCal, endCal); } /** diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestTriggerTask.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestTriggerTask.java index 52f2884e189..166aa5ab62c 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestTriggerTask.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestTriggerTask.java @@ -15,12 +15,16 @@ */ package com.evolveum.midpoint.model.intest; +import static java.util.Collections.singleton; +import static org.springframework.test.util.AssertionErrors.assertTrue; import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertNull; import static org.testng.AssertJUnit.assertNotNull; import javax.xml.datatype.XMLGregorianCalendar; +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.test.IntegrationTestTools; import com.evolveum.midpoint.xml.ns._public.common.common_3.ConflictResolutionActionType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.annotation.DirtiesContext; @@ -100,13 +104,13 @@ public void test100ImportScannerTask() throws Exception { // THEN TestUtil.displayThen(TEST_NAME); XMLGregorianCalendar endCal = clock.currentTimeXMLGregorianCalendar(); - assertLastRecomputeTimestamp(TASK_TRIGGER_SCANNER_OID, startCal, endCal); + assertLastScanTimestamp(TASK_TRIGGER_SCANNER_OID, startCal, endCal); assertNotNull("Trigger was not called", testTriggerHandler.getLastObject()); assertEquals("Trigger was called incorrect number of times", 1, testTriggerHandler.getInvocationCount()); assertNoTrigger(UserType.class, USER_JACK_OID); - assertLastRecomputeTimestamp(TASK_TRIGGER_SCANNER_OID, startCal, endCal); + assertLastScanTimestamp(TASK_TRIGGER_SCANNER_OID, startCal, endCal); } @Test @@ -134,7 +138,7 @@ public void test105NoTrigger() throws Exception { assertNull("Trigger was called while not expecting it", testTriggerHandler.getLastObject()); assertNoTrigger(UserType.class, USER_JACK_OID); - assertLastRecomputeTimestamp(TASK_TRIGGER_SCANNER_OID, startCal, endCal); + assertLastScanTimestamp(TASK_TRIGGER_SCANNER_OID, startCal, endCal); } @Test @@ -165,7 +169,7 @@ public void test110TriggerCalledAgain() throws Exception { assertEquals("Trigger was called incorrect number of times", 1, testTriggerHandler.getInvocationCount()); assertNoTrigger(UserType.class, USER_JACK_OID); - assertLastRecomputeTimestamp(TASK_TRIGGER_SCANNER_OID, startCal, endCal); + assertLastScanTimestamp(TASK_TRIGGER_SCANNER_OID, startCal, endCal); } @Test @@ -199,7 +203,7 @@ public void test120TwoTriggers() throws Exception { assertEquals("Trigger was called wrong number of times", 2, testTriggerHandler.getInvocationCount()); assertNoTrigger(UserType.class, USER_JACK_OID); - assertLastRecomputeTimestamp(TASK_TRIGGER_SCANNER_OID, startCal, endCal); + assertLastScanTimestamp(TASK_TRIGGER_SCANNER_OID, startCal, endCal); } @Test @@ -227,7 +231,7 @@ public void test150NoTriggerAgain() throws Exception { assertNull("Trigger was called while not expecting it", testTriggerHandler.getLastObject()); assertNoTrigger(UserType.class, USER_JACK_OID); - assertLastRecomputeTimestamp(TASK_TRIGGER_SCANNER_OID, startCal, endCal); + assertLastScanTimestamp(TASK_TRIGGER_SCANNER_OID, startCal, endCal); } @Test @@ -259,7 +263,59 @@ public void test200TwoDistantTriggers() throws Exception { assertEquals("Trigger was called wrong number of times", 1, testTriggerHandler.getInvocationCount()); assertTrigger(getUser(USER_JACK_OID), MockTriggerHandler.HANDLER_URI, startCalPlus5days, 100L); - assertLastRecomputeTimestamp(TASK_TRIGGER_SCANNER_OID, startCal, endCal); + assertLastScanTimestamp(TASK_TRIGGER_SCANNER_OID, startCal, endCal); } + // MID-4474 + @Test + public void test210InterruptedScanner() throws Exception { + final String TEST_NAME = "test210InterruptedScanner"; + TestUtil.displayTestTitle(this, TEST_NAME); + + // GIVEN + Task task = createTask(TestTriggerTask.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + testTriggerHandler.reset(); + + // to avoid unexpected runs of this task that would move lastScanTimestamp + boolean suspended = taskManager.suspendTasks(singleton(TASK_TRIGGER_SCANNER_OID), 20000L, result); + assertTrue("trigger scanner task was not suspended (before operation)", suspended); + + XMLGregorianCalendar lastScanTimestampBefore = getLastScanTimestamp(TASK_TRIGGER_SCANNER_OID); + assertNotNull(lastScanTimestampBefore); + + XMLGregorianCalendar startCal = clock.currentTimeXMLGregorianCalendar(); + XMLGregorianCalendar startCalPlus5days = XmlTypeConverter.createXMLGregorianCalendar(startCal); + startCalPlus5days.add(XmlTypeConverter.createDuration("P5D")); + replaceTriggers(USER_JACK_OID, Arrays.asList(startCal, startCalPlus5days), MockTriggerHandler.HANDLER_URI); + + final long ONE_DAY = 86400L * 1000L; + testTriggerHandler.setDelay(ONE_DAY); + + taskManager.resumeTasks(singleton(TASK_TRIGGER_SCANNER_OID), result); + + /// WHEN + TestUtil.displayWhen(TEST_NAME); + IntegrationTestTools.waitFor("Waiting for trigger handler invocation", () -> testTriggerHandler.getInvocationCount() > 0, 60000); + suspended = taskManager.suspendTasks(singleton(TASK_TRIGGER_SCANNER_OID), 20000L, result); + assertTrue("trigger scanner task was not suspended (after operation)", suspended); + + // THEN + TestUtil.displayThen(TEST_NAME); + + // THEN + assertNotNull("Trigger was not called", testTriggerHandler.getLastObject()); + assertEquals("Trigger was called wrong number of times", 1, testTriggerHandler.getInvocationCount()); + PrismObject jackAfter = getUser(USER_JACK_OID); + display("jack after", jackAfter); + assertTrigger(jackAfter, MockTriggerHandler.HANDLER_URI, startCalPlus5days, 100L); + assertEquals("Wrong # of triggers on jack", 1, jackAfter.asObjectable().getTrigger().size()); + + XMLGregorianCalendar lastScanTimestampAfter = getLastScanTimestamp(TASK_TRIGGER_SCANNER_OID); + + // this assert may fail occasionally if the trigger scanner would start in between (we'll see how often) + assertEquals("Last scan timestamp was changed", lastScanTimestampBefore, lastScanTimestampAfter); + } + + // trigger scanner task is suspended here; and handler is set to a delay of one day (reset will clear that) } diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/AbstractDirectManualResourceTest.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/AbstractDirectManualResourceTest.java index 7e9f13d3ebf..ba0049a377a 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/AbstractDirectManualResourceTest.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/AbstractDirectManualResourceTest.java @@ -39,6 +39,8 @@ import com.evolveum.midpoint.schema.PointInTimeType; import com.evolveum.midpoint.schema.SelectorOptions; import com.evolveum.midpoint.schema.constants.SchemaConstants; +import com.evolveum.midpoint.schema.internals.InternalMonitor; +import com.evolveum.midpoint.schema.internals.InternalOperationClasses; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.logging.Trace; @@ -64,6 +66,9 @@ public abstract class AbstractDirectManualResourceTest extends AbstractManualRes protected static final File RESOURCE_MANUAL_FILE = new File(TEST_DIR, "resource-manual.xml"); protected static final String RESOURCE_MANUAL_OID = "0ef80ab8-2906-11e7-b81a-3f343e28c264"; + + protected static final File RESOURCE_MANUAL_CAPABILITIES_FILE = new File(TEST_DIR, "resource-manual-capabilities.xml"); + protected static final String RESOURCE_MANUAL_CAPABILITIES_OID = "0ef80ab8-2906-11e7-b81a-3f343e28c264"; protected static final File RESOURCE_SEMI_MANUAL_FILE = new File(TEST_DIR, "resource-semi-manual.xml"); protected static final String RESOURCE_SEMI_MANUAL_OID = "aea5a57c-2904-11e7-8020-7b121a9e3595"; @@ -118,6 +123,7 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti super.initSystem(initTask, initResult); addObject(USER_BARBOSSA_FILE); + InternalMonitor.setTrace(InternalOperationClasses.REPOSITORY_OPERATIONS, true); } @Override @@ -198,6 +204,8 @@ public void test220ModifyUserWillDisable() throws Exception { assertNotNull("No async reference in result", willLastCaseOid); assertCase(willLastCaseOid, SchemaConstants.CASE_STATE_OPEN); + + assertSteadyResources(); } /** @@ -284,6 +292,8 @@ public void test230ModifyAccountWillChangePasswordAndEnable() throws Exception { assertCase(willLastCaseOid, SchemaConstants.CASE_STATE_OPEN); assertCase(willSecondLastCaseOid, SchemaConstants.CASE_STATE_OPEN); + + assertSteadyResources(); } /** @@ -375,6 +385,8 @@ public void test240CloseDisableCaseAndReadAccountWill() throws Exception { assertCase(willLastCaseOid, SchemaConstants.CASE_STATE_CLOSED); assertCase(willSecondLastCaseOid, SchemaConstants.CASE_STATE_OPEN); + + assertSteadyResources(); } /** @@ -464,6 +476,8 @@ public void test250RecomputeWillAfter5min() throws Exception { assertCase(willLastCaseOid, SchemaConstants.CASE_STATE_CLOSED); assertCase(willSecondLastCaseOid, SchemaConstants.CASE_STATE_OPEN); + + assertSteadyResources(); } @Test @@ -517,6 +531,8 @@ public void test252UpdateBackingStoreAndGetAccountWill() throws Exception { assertCase(willLastCaseOid, SchemaConstants.CASE_STATE_CLOSED); assertCase(willSecondLastCaseOid, SchemaConstants.CASE_STATE_OPEN); + + assertSteadyResources(); } /** @@ -610,6 +626,8 @@ public void test260ClosePasswordChangeCaseAndRecomputeWill() throws Exception { assertCase(willLastCaseOid, SchemaConstants.CASE_STATE_CLOSED); assertCase(willSecondLastCaseOid, SchemaConstants.CASE_STATE_CLOSED); + + assertSteadyResources(); } /** @@ -701,6 +719,8 @@ public void test270RecomputeWillAfter7min() throws Exception { assertCase(willLastCaseOid, SchemaConstants.CASE_STATE_CLOSED); assertCase(willSecondLastCaseOid, SchemaConstants.CASE_STATE_CLOSED); + + assertSteadyResources(); } @Test @@ -754,6 +774,8 @@ public void test272UpdateBackingStoreAndGetAccountWill() throws Exception { assertCase(willLastCaseOid, SchemaConstants.CASE_STATE_CLOSED); assertCase(willSecondLastCaseOid, SchemaConstants.CASE_STATE_CLOSED); + + assertSteadyResources(); } /** @@ -838,6 +860,8 @@ public void test280RecomputeWillAfter5min() throws Exception { assertCase(willLastCaseOid, SchemaConstants.CASE_STATE_CLOSED); assertCase(willSecondLastCaseOid, SchemaConstants.CASE_STATE_CLOSED); + + assertSteadyResources(); } /** @@ -902,6 +926,8 @@ public void test290RecomputeWillAfter5min() throws Exception { assertCase(willLastCaseOid, SchemaConstants.CASE_STATE_CLOSED); assertCase(willSecondLastCaseOid, SchemaConstants.CASE_STATE_CLOSED); + + assertSteadyResources(); } @Test @@ -911,6 +937,8 @@ public void test300UnassignAccountWill() throws Exception { // GIVEN Task task = createTask(TEST_NAME); OperationResult result = task.getResult(); + + assertSteadyResources(); accountWillReqestTimestampStart = clock.currentTimeXMLGregorianCalendar(); @@ -925,6 +953,8 @@ public void test300UnassignAccountWill() throws Exception { accountWillReqestTimestampEnd = clock.currentTimeXMLGregorianCalendar(); + assertSteadyResources(); + PrismObject shadowRepo = repositoryService.getObject(ShadowType.class, accountWillOid, null, result); display("Repo shadow", shadowRepo); assertPendingOperationDeltas(shadowRepo, 1); @@ -962,6 +992,8 @@ public void test300UnassignAccountWill() throws Exception { task, result); display("Model shadow (future)", shadowModelFuture); assertWillUnassignedFuture(shadowModelFuture, true); + + assertSteadyResources(); // Make sure that the account is still linked PrismObject userAfter = getUser(userWillOid); @@ -973,6 +1005,8 @@ public void test300UnassignAccountWill() throws Exception { assertNotNull("No async reference in result", willLastCaseOid); assertCase(willLastCaseOid, SchemaConstants.CASE_STATE_OPEN); + + assertSteadyResources(); } /** @@ -1043,6 +1077,8 @@ public void test302RecomputeWill() throws Exception { assertNotNull("No async reference in result", willLastCaseOid); assertCase(willLastCaseOid, SchemaConstants.CASE_STATE_OPEN); + + assertSteadyResources(); } /** @@ -1103,6 +1139,8 @@ public void test310CloseCaseAndRecomputeWill() throws Exception { assertWillUnassignedFuture(shadowModelFuture, true); assertCase(willLastCaseOid, SchemaConstants.CASE_STATE_CLOSED); + + assertSteadyResources(); } protected void assertUnassignedShadow(PrismObject shadow, ActivationStatusType expectAlternativeActivationStatus) { @@ -1161,6 +1199,8 @@ public void test320RecomputeWillAfter5min() throws Exception { assertWillUnassignedFuture(shadowModelFuture, true); assertCase(willLastCaseOid, SchemaConstants.CASE_STATE_CLOSED); + + assertSteadyResources(); } @Test @@ -1212,6 +1252,8 @@ public void test330UpdateBackingStoreAndRecomputeWill() throws Exception { assertWillUnassignedFuture(shadowModelFuture, false); assertCase(willLastCaseOid, SchemaConstants.CASE_STATE_CLOSED); + + assertSteadyResources(); } // TODO: nofetch, nofetch+future @@ -1242,6 +1284,8 @@ public void test340RecomputeWillAfter25min() throws Exception { assertDeprovisionedTimedOutUser(userAfter, accountWillOid); assertCase(willLastCaseOid, SchemaConstants.CASE_STATE_CLOSED); + + assertSteadyResources(); } // TODO: create, close case, then update backing store. diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/AbstractManualResourceTest.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/AbstractManualResourceTest.java index 5b73f8b34aa..c1b12834ae8 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/AbstractManualResourceTest.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/AbstractManualResourceTest.java @@ -19,10 +19,10 @@ */ package com.evolveum.midpoint.model.intest.manual; -import static org.testng.AssertJUnit.assertNull; import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertFalse; import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertNull; import static org.testng.AssertJUnit.assertTrue; import java.io.File; @@ -55,10 +55,12 @@ import com.evolveum.midpoint.model.intest.AbstractConfiguredModelIntegrationTest; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.prism.query.ObjectQuery; import com.evolveum.midpoint.prism.util.PrismTestUtil; import com.evolveum.midpoint.schema.CapabilityUtil; import com.evolveum.midpoint.schema.GetOperationOptions; import com.evolveum.midpoint.schema.PointInTimeType; +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.SchemaConstants; @@ -69,6 +71,7 @@ import com.evolveum.midpoint.schema.processor.ResourceSchema; import com.evolveum.midpoint.schema.processor.ResourceSchemaImpl; import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.schema.util.ObjectQueryUtil; import com.evolveum.midpoint.schema.util.ObjectTypeUtil; import com.evolveum.midpoint.schema.util.ResourceTypeUtil; import com.evolveum.midpoint.task.api.Task; @@ -78,6 +81,7 @@ import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.xml.ns._public.common.api_types_3.ImportOptionsType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ActivationStatusType; import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentPolicyEnforcementType; import com.evolveum.midpoint.xml.ns._public.common.common_3.CachingMetadataType; @@ -181,6 +185,8 @@ public abstract class AbstractManualResourceTest extends AbstractConfiguredModel protected String jackLastCaseOid; + private String lastResourceVersion; + @Override public void initSystem(Task initTask, OperationResult initResult) throws Exception { super.initSystem(initTask, initResult); @@ -280,8 +286,12 @@ public void test000Sanity() throws Exception { } @Test - public void test003Connection() throws Exception { - final String TEST_NAME = "test003Connection"; + public void test012TestConnection() throws Exception { + final String TEST_NAME = "test012TestConnection"; + testConnection(TEST_NAME, false); + } + + public void testConnection(final String TEST_NAME, boolean initialized) throws Exception { displayTestTitle(TEST_NAME); // GIVEN Task task = createTask(TEST_NAME); @@ -292,17 +302,26 @@ public void test003Connection() throws Exception { null, result).asObjectable(); Element resourceXsdSchemaElementBefore = ResourceTypeUtil.getResourceXsdSchema(resourceBefore); - assertResourceSchemaBeforeTest(resourceXsdSchemaElementBefore); + if (!initialized) { + assertResourceSchemaBeforeTest(resourceXsdSchemaElementBefore); + } - CapabilitiesType capabilities = resourceBefore.getCapabilities(); - if (capabilities != null) { - AssertJUnit.assertNull("Native capabilities present before test connection. Bad test setup?", capabilities.getNative()); + CapabilitiesType capabilitiesBefore = resourceBefore.getCapabilities(); + if (initialized || nativeCapabilitiesEntered()) { + AssertJUnit.assertNotNull("Native capabilities missing before test connection. Bad test setup?", capabilitiesBefore); + AssertJUnit.assertNotNull("Native capabilities missing before test connection. Bad test setup?", capabilitiesBefore.getNative()); + } else { + if (capabilitiesBefore != null) { + AssertJUnit.assertNull("Native capabilities present before test connection. Bad test setup?", capabilitiesBefore.getNative()); + } } // WHEN + displayWhen(TEST_NAME); OperationResult testResult = modelService.testResource(getResourceOid(), task); // THEN + displayThen(TEST_NAME); display("Test result", testResult); TestUtil.assertSuccess("Test resource failed (result)", testResult); @@ -316,30 +335,46 @@ public void test003Connection() throws Exception { assertNotNull("No schema after test connection", resourceXsdSchemaElementAfter); String resourceXml = prismContext.serializeObjectToString(resourceRepoAfter, PrismContext.LANG_XML); - display("Resource XML", resourceXml); + display("Resource XML after test connection", resourceXml); - CachingMetadataType cachingMetadata = xmlSchemaTypeAfter.getCachingMetadata(); - assertNotNull("No caching metadata", cachingMetadata); - assertNotNull("No retrievalTimestamp", cachingMetadata.getRetrievalTimestamp()); - assertNotNull("No serialNumber", cachingMetadata.getSerialNumber()); + CachingMetadataType schemaCachingMetadata = xmlSchemaTypeAfter.getCachingMetadata(); + assertNotNull("No caching metadata", schemaCachingMetadata); + assertNotNull("No retrievalTimestamp", schemaCachingMetadata.getRetrievalTimestamp()); + assertNotNull("No serialNumber", schemaCachingMetadata.getSerialNumber()); Element xsdElement = ObjectTypeUtil.findXsdElement(xmlSchemaTypeAfter); ResourceSchema parsedSchema = ResourceSchemaImpl.parse(xsdElement, resourceBefore.toString(), prismContext); assertNotNull("No schema after parsing", parsedSchema); - // schema will be checked in next test + CapabilitiesType capabilitiesRepoAfter = resourceTypeRepoAfter.getCapabilities(); + AssertJUnit.assertNotNull("Capabilities missing after test connection.", capabilitiesRepoAfter); + AssertJUnit.assertNotNull("Native capabilities missing after test connection.", capabilitiesRepoAfter.getNative()); + AssertJUnit.assertNotNull("Capabilities caching metadata missing after test connection.", capabilitiesRepoAfter.getCachingMetadata()); + + ResourceType resourceModelAfter = modelService.getObject(ResourceType.class, getResourceOid(), null, null, result).asObjectable(); + + rememberSteadyResources(); + + CapabilitiesType capabilitiesModelAfter = resourceModelAfter.getCapabilities(); + AssertJUnit.assertNotNull("Capabilities missing after test connection (model)", capabilitiesModelAfter); + AssertJUnit.assertNotNull("Native capabilities missing after test connection (model)", capabilitiesModelAfter.getNative()); + AssertJUnit.assertNotNull("Capabilities caching metadata missing after test connection (model)", capabilitiesModelAfter.getCachingMetadata()); } + protected boolean nativeCapabilitiesEntered() { + return false; + } + protected abstract void assertResourceSchemaBeforeTest(Element resourceXsdSchemaElementBefore); @Test - public void test004Configuration() throws Exception { - final String TEST_NAME = "test004Configuration"; + public void test014Configuration() throws Exception { + final String TEST_NAME = "test014Configuration"; displayTestTitle(TEST_NAME); // GIVEN OperationResult result = new OperationResult(AbstractManualResourceTest.class.getName() + "." + TEST_NAME); - + // WHEN resource = modelService.getObject(ResourceType.class, getResourceOid(), null, null, result); resourceType = resource.asObjectable(); @@ -355,15 +390,16 @@ public void test004Configuration() throws Exception { // PrismContainerDefinition confPropDef = confingurationPropertiesContainer.getDefinition(); // assertNotNull("No configuration properties container definition", confPropDef); + assertSteadyResources(); } @Test - public void test005ParsedSchema() throws Exception { - final String TEST_NAME = "test005ParsedSchema"; + public void test016ParsedSchema() throws Exception { + final String TEST_NAME = "test016ParsedSchema"; displayTestTitle(TEST_NAME); // GIVEN OperationResult result = new OperationResult(AbstractManualResourceTest.class.getName() + "." + TEST_NAME); - + // THEN // The returned type should have the schema pre-parsed assertNotNull(RefinedResourceSchemaImpl.hasParsedSchema(resourceType)); @@ -401,11 +437,17 @@ public void test005ParsedSchema() throws Exception { assertTrue("No fullname create", fullnameDef.canAdd()); assertTrue("No fullname update", fullnameDef.canModify()); assertTrue("No fullname read", fullnameDef.canRead()); + + assertSteadyResources(); } @Test - public void test006Capabilities() throws Exception { - final String TEST_NAME = "test006Capabilities"; + public void test017Capabilities() throws Exception { + final String TEST_NAME = "test017Capabilities"; + testCapabilities(TEST_NAME); + } + + public void testCapabilities(final String TEST_NAME) throws Exception { displayTestTitle(TEST_NAME); // GIVEN @@ -415,10 +457,15 @@ public void test006Capabilities() throws Exception { ResourceType resource = modelService.getObject(ResourceType.class, getResourceOid(), null, null, result).asObjectable(); // THEN - display("Resource from provisioninig", resource); - display("Resource from provisioninig (XML)", PrismTestUtil.serializeObjectToString(resource.asPrismObject(), PrismContext.LANG_XML)); + display("Resource from model", resource); + display("Resource from model (XML)", PrismTestUtil.serializeObjectToString(resource.asPrismObject(), PrismContext.LANG_XML)); - CapabilityCollectionType nativeCapabilities = resource.getCapabilities().getNative(); + assertSteadyResources(); + + CapabilitiesType capabilities = resource.getCapabilities(); + assertNotNull("Missing capability caching metadata", capabilities.getCachingMetadata()); + + CapabilityCollectionType nativeCapabilities = capabilities.getNative(); List nativeCapabilitiesList = nativeCapabilities.getAny(); assertFalse("Empty capabilities returned",nativeCapabilitiesList.isEmpty()); @@ -437,7 +484,192 @@ public void test006Capabilities() throws Exception { for (Object capability : effectiveCapabilities) { System.out.println("Capability: "+CapabilityUtil.getCapabilityDisplayName(capability)+" : "+capability); } + + assertSteadyResources(); + } + + /** + * MID-4472, MID-4174 + */ + @Test + public void test018ResourceCaching() throws Exception { + final String TEST_NAME = "test018ResourceCaching"; + testResourceCaching(TEST_NAME); + } + + public void testResourceCaching(final String TEST_NAME) throws Exception { + displayTestTitle(TEST_NAME); + // GIVEN + Task task = createTask(TEST_NAME); + OperationResult result = task.getResult(); + + PrismObject resourceReadonlyBefore = modelService.getObject( + ResourceType.class, getResourceOid(), GetOperationOptions.createReadOnlyCollection(), task, result); + + assertSteadyResources(); + + // WHEN + displayWhen(TEST_NAME); + PrismObject resourceReadOnlyAgain = modelService.getObject( + ResourceType.class, getResourceOid(), GetOperationOptions.createReadOnlyCollection(), task, result); + + assertSteadyResources(); + + // WHEN + displayWhen(TEST_NAME); + PrismObject resourceAgain = modelService.getObject( + ResourceType.class, getResourceOid(), null, task, result); + + // THEN + displayThen(TEST_NAME); + assertSuccess(result); + +// assertTrue("Resource instance changed", resourceBefore == resourceReadOnlyAgain); + + assertSteadyResources(); + } + + @Test + public void test020ReimportResource() throws Exception { + final String TEST_NAME = "test020ReimportResource"; + displayTestTitle(TEST_NAME); + // GIVEN + Task task = createTask(TEST_NAME); + OperationResult result = task.getResult(); + + ImportOptionsType options = new ImportOptionsType(); + options.setOverwrite(true); + + // WHEN + displayWhen(TEST_NAME); + modelService.importObjectsFromFile(getResourceFile(), options, task, result); + + // THEN + displayThen(TEST_NAME); + assertSuccess(result); + } + + @Test + public void test022TestConnection() throws Exception { + final String TEST_NAME = "test022TestConnection"; + testConnection(TEST_NAME, false); + } + + @Test + public void test027Capabilities() throws Exception { + final String TEST_NAME = "test027Capabilities"; + testCapabilities(TEST_NAME); + } + + /** + * MID-4472, MID-4174 + */ + @Test + public void test028ResourceCaching() throws Exception { + final String TEST_NAME = "test028ResourceCaching"; + testResourceCaching(TEST_NAME); + } + + @Test + public void test030ReimportResourceAgain() throws Exception { + final String TEST_NAME = "test030ReimportResourceAgain"; + displayTestTitle(TEST_NAME); + // GIVEN + Task task = createTask(TEST_NAME); + OperationResult result = task.getResult(); + + ImportOptionsType options = new ImportOptionsType(); + options.setOverwrite(true); + + // WHEN + displayWhen(TEST_NAME); + modelService.importObjectsFromFile(getResourceFile(), options, task, result); + // THEN + displayThen(TEST_NAME); + assertSuccess(result); + } + + // This time simply try to use the resource without any attempt to test connection + @Test + public void test032UseResource() throws Exception { + final String TEST_NAME = "test032UseResource"; + displayTestTitle(TEST_NAME); + // GIVEN + Task task = createTask(TEST_NAME); + OperationResult result = task.getResult(); + + ObjectQuery query = ObjectQueryUtil.createResourceAndKindIntent(getResourceOid(), ShadowKindType.ACCOUNT, null, prismContext); + + // WHEN + displayWhen(TEST_NAME); + SearchResultList> accounts = modelService.searchObjects(ShadowType.class, query, null, task, result); + + // THEN + displayThen(TEST_NAME); + assertSuccess(result); + + display("Found accounts", accounts); + assertEquals("unexpected accounts: "+accounts, 0, accounts.size()); + + rememberSteadyResources(); + + PrismObject resourceRepoAfter = repositoryService.getObject(ResourceType.class, getResourceOid(), null, result); + ResourceType resourceTypeRepoAfter = resourceRepoAfter.asObjectable(); + display("Resource after test", resourceTypeRepoAfter); + + XmlSchemaType xmlSchemaTypeAfter = resourceTypeRepoAfter.getSchema(); + assertNotNull("No schema after test connection", xmlSchemaTypeAfter); + Element resourceXsdSchemaElementAfter = ResourceTypeUtil.getResourceXsdSchema(resourceTypeRepoAfter); + assertNotNull("No schema after test connection", resourceXsdSchemaElementAfter); + + String resourceXml = prismContext.serializeObjectToString(resourceRepoAfter, PrismContext.LANG_XML); + display("Resource XML after test connection", resourceXml); + + CachingMetadataType schemaCachingMetadata = xmlSchemaTypeAfter.getCachingMetadata(); + assertNotNull("No schema caching metadata", schemaCachingMetadata); + assertNotNull("No schema caching metadata retrievalTimestamp", schemaCachingMetadata.getRetrievalTimestamp()); + assertNotNull("No schema caching metadata serialNumber", schemaCachingMetadata.getSerialNumber()); + + ResourceType resourceModelAfter = modelService.getObject(ResourceType.class, getResourceOid(), null, null, result).asObjectable(); + + Element xsdElement = ObjectTypeUtil.findXsdElement(xmlSchemaTypeAfter); + ResourceSchema parsedSchema = ResourceSchemaImpl.parse(xsdElement, resourceModelAfter.toString(), prismContext); + assertNotNull("No schema after parsing", parsedSchema); + CapabilitiesType capabilitiesRepoAfter = resourceTypeRepoAfter.getCapabilities(); + AssertJUnit.assertNotNull("Capabilities missing after test connection.", capabilitiesRepoAfter); + AssertJUnit.assertNotNull("Native capabilities missing after test connection.", capabilitiesRepoAfter.getNative()); + AssertJUnit.assertNotNull("Capabilities caching metadata missing after test connection.", capabilitiesRepoAfter.getCachingMetadata()); + + CapabilitiesType capabilitiesModelAfter = resourceModelAfter.getCapabilities(); + AssertJUnit.assertNotNull("Capabilities missing after test connection (model)", capabilitiesModelAfter); + AssertJUnit.assertNotNull("Native capabilities missing after test connection (model)", capabilitiesModelAfter.getNative()); + AssertJUnit.assertNotNull("Capabilities caching metadata missing after test connection (model)", capabilitiesModelAfter.getCachingMetadata()); + } + + @Test + public void test037Capabilities() throws Exception { + final String TEST_NAME = "test037Capabilities"; + testCapabilities(TEST_NAME); + } + + /** + * MID-4472, MID-4174 + */ + @Test + public void test038ResourceCaching() throws Exception { + final String TEST_NAME = "test038ResourceCaching"; + testResourceCaching(TEST_NAME); + } + + /** + * Make sure the resource is fully initialized, so steady resource asserts + * in subsequent tests will work as expected. + */ + @Test + public void test099TestConnection() throws Exception { + final String TEST_NAME = "test099TestConnection"; + testConnection(TEST_NAME, true); } @Test @@ -477,6 +709,8 @@ public void test101GetAccountWillFuture() throws Exception { assertShadowExists(shadowModel, true); // TODO // assertShadowPassword(shadowProvisioning); + + assertSteadyResources(); } @Test @@ -496,6 +730,8 @@ public void test102RecomputeWill() throws Exception { assertSuccess(result); assertAccountWillAfterAssign(TEST_NAME, USER_WILL_FULL_NAME, PendingOperationExecutionStatusType.EXECUTION_PENDING); + + assertSteadyResources(); } /** @@ -523,6 +759,8 @@ public void test103RunPropagation() throws Exception { assertCounterIncrement(InternalCounters.CONNECTOR_MODIFICATION_COUNT, 1); assertAccountWillAfterAssign(TEST_NAME, USER_WILL_FULL_NAME, PendingOperationExecutionStatusType.EXECUTING); + + assertSteadyResources(); } @Test @@ -544,6 +782,8 @@ public void test104RecomputeWill() throws Exception { assertCounterIncrement(InternalCounters.CONNECTOR_MODIFICATION_COUNT, 0); assertAccountWillAfterAssign(TEST_NAME, USER_WILL_FULL_NAME, PendingOperationExecutionStatusType.EXECUTING); + + assertSteadyResources(); } /** @@ -567,6 +807,8 @@ public void test105RunPropagationAgain() throws Exception { assertCounterIncrement(InternalCounters.CONNECTOR_MODIFICATION_COUNT, 0); assertAccountWillAfterAssign(TEST_NAME, USER_WILL_FULL_NAME, PendingOperationExecutionStatusType.EXECUTING); + + assertSteadyResources(); } @Test @@ -610,6 +852,8 @@ public void test106AddToBackingStoreAndGetAccountWill() throws Exception { assertShadowActivationAdministrativeStatusFromCache(shadowRepo, ActivationStatusType.ENABLED); assertNoShadowPassword(shadowRepo); assertShadowExists(shadowRepo, supportsBackingStore()); + + assertSteadyResources(); } @Test @@ -653,6 +897,8 @@ public void test108GetAccountWillFuture() throws Exception { assertShadowActivationAdministrativeStatusFromCache(shadowRepo, ActivationStatusType.ENABLED); assertNoShadowPassword(shadowRepo); assertShadowExists(shadowRepo, supportsBackingStore()); + + assertSteadyResources(); } /** @@ -681,7 +927,9 @@ public void test110CloseCaseAndRecomputeWill() throws Exception { accountWillCompletionTimestampEnd = clock.currentTimeXMLGregorianCalendar(); - assertWillAfterCreateCaseClosed(TEST_NAME, true); + assertWillAfterCreateCaseClosed(TEST_NAME, true); + + assertSteadyResources(); } /** @@ -705,6 +953,8 @@ public void test114RunPropagation() throws Exception { assertCounterIncrement(InternalCounters.CONNECTOR_MODIFICATION_COUNT, 0); assertWillAfterCreateCaseClosed(TEST_NAME, true); + + assertSteadyResources(); } /** @@ -744,6 +994,8 @@ public void test120RecomputeWillAfter5min() throws Exception { accountWillCompletionTimestampStart, accountWillCompletionTimestampEnd); assertCase(willLastCaseOid, SchemaConstants.CASE_STATE_CLOSED); + + assertSteadyResources(); } /** @@ -776,6 +1028,8 @@ public void test130RecomputeWillAfter25min() throws Exception { assertNoPendingOperation(shadowModel); assertCase(willLastCaseOid, SchemaConstants.CASE_STATE_CLOSED); + + assertSteadyResources(); } @Test @@ -805,6 +1059,8 @@ accountWillOid, new ItemPath(ShadowType.F_ATTRIBUTES, ATTR_FULLNAME_QNAME), pris accountWillReqestTimestampEnd = clock.currentTimeXMLGregorianCalendar(); assertAccountWillAfterFillNameModification(TEST_NAME, PendingOperationExecutionStatusType.EXECUTION_PENDING); + + assertSteadyResources(); } @Test @@ -824,6 +1080,8 @@ public void test202RecomputeWill() throws Exception { assertSuccess(result); assertAccountWillAfterFillNameModification(TEST_NAME, PendingOperationExecutionStatusType.EXECUTION_PENDING); + + assertSteadyResources(); } @Test @@ -842,6 +1100,8 @@ public void test203RunPropagation() throws Exception { displayThen(TEST_NAME); assertAccountWillAfterFillNameModification(TEST_NAME, PendingOperationExecutionStatusType.EXECUTING); + + assertSteadyResources(); } @Test @@ -861,6 +1121,8 @@ public void test204RecomputeWill() throws Exception { assertSuccess(result); assertAccountWillAfterFillNameModification(TEST_NAME, PendingOperationExecutionStatusType.EXECUTING); + + assertSteadyResources(); } /** @@ -936,6 +1198,8 @@ public void test206CloseCaseAndRecomputeWill() throws Exception { assertShadowPassword(shadowProvisioningFuture); assertCase(willLastCaseOid, SchemaConstants.CASE_STATE_CLOSED); + + assertSteadyResources(); } @@ -998,6 +1262,8 @@ public void test210RecomputeWillAfter5min() throws Exception { assertShadowPassword(shadowModelFuture); assertCase(willLastCaseOid, SchemaConstants.CASE_STATE_CLOSED); + + assertSteadyResources(); } @Test @@ -1051,6 +1317,8 @@ public void test212UpdateBackingStoreAndGetAccountWill() throws Exception { assertShadowPassword(shadowModelFuture); assertCase(willLastCaseOid, SchemaConstants.CASE_STATE_CLOSED); + + assertSteadyResources(); } protected boolean are9xxTestsEnabled() { @@ -1421,6 +1689,8 @@ protected void assignWillRoleOne(final String TEST_NAME, String expectedFullName accountWillReqestTimestampEnd = clock.currentTimeXMLGregorianCalendar(); assertAccountWillAfterAssign(TEST_NAME, expectedFullName, executionStage); + + assertSteadyResources(); } protected void assertAccountWillAfterAssign(final String TEST_NAME, String expectedFullName, PendingOperationExecutionStatusType executionStage) throws Exception { @@ -1768,5 +2038,29 @@ protected void assertCase(String oid, String expectedState, PendingOperationExec protected void runPropagation() throws Exception { // nothing by default } + + @Override + protected void rememberSteadyResources() { + super.rememberSteadyResources(); + OperationResult result = new OperationResult("rememberSteadyResources"); + try { + lastResourceVersion = repositoryService.getVersion(ResourceType.class, getResourceOid(), result); + } catch (ObjectNotFoundException | SchemaException e) { + throw new RuntimeException(e.getMessage(), e); + } + } + + @Override + protected void assertSteadyResources() { + super.assertSteadyResources(); + String currentResourceVersion; + try { + OperationResult result = new OperationResult("assertSteadyResources"); + currentResourceVersion = repositoryService.getVersion(ResourceType.class, getResourceOid(), result); + } catch (ObjectNotFoundException | SchemaException e) { + throw new RuntimeException(e.getMessage(), e); + } + assertEquals("Resource version mismatch", lastResourceVersion, currentResourceVersion); + } } diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/TestManualCapabilities.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/TestManualCapabilities.java new file mode 100644 index 00000000000..45a067fe413 --- /dev/null +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/TestManualCapabilities.java @@ -0,0 +1,54 @@ +/* + * 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.model.intest.manual; + +import java.io.File; + +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.springframework.test.context.ContextConfiguration; +import org.testng.AssertJUnit; +import org.testng.annotations.Listeners; +import org.w3c.dom.Element; + +/** + * @author Radovan Semancik + */ +@ContextConfiguration(locations = {"classpath:ctx-model-intest-test-main.xml"}) +@DirtiesContext(classMode = ClassMode.AFTER_CLASS) +@Listeners({ com.evolveum.midpoint.tools.testng.AlphabeticalMethodInterceptor.class }) +public class TestManualCapabilities extends TestManual { + + @Override + protected File getResourceFile() { + return RESOURCE_MANUAL_CAPABILITIES_FILE; + } + + @Override + protected boolean nativeCapabilitiesEntered() { + return true; + } + + @Override + protected int getNumberOfAccountAttributeDefinitions() { + return 5; + } + +} \ No newline at end of file diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/TestSemiManualDisable.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/TestSemiManualDisable.java index 5bad3b211cc..a52d250b8a3 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/TestSemiManualDisable.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/TestSemiManualDisable.java @@ -94,6 +94,11 @@ protected File getRoleTwoFile() { return ROLE_TWO_SEMI_MANUAL_DISABLE_FILE; } + @Override + protected boolean nativeCapabilitiesEntered() { + return true; + } + @Override protected void assertUnassignedShadow(PrismObject shadow, ActivationStatusType expectAlternativeActivationStatus) { assertShadowNotDead(shadow); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/TestSemiManualDisableSlowProposed.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/TestSemiManualDisableSlowProposed.java index 6704ec6b1ab..07138dd1e57 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/TestSemiManualDisableSlowProposed.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/TestSemiManualDisableSlowProposed.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2017 Evolveum + * 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. @@ -95,6 +95,10 @@ protected File getRoleTwoFile() { return ROLE_TWO_SEMI_MANUAL_DISABLE_SLOW_PROPOSED_FILE; } + @Override + protected boolean nativeCapabilitiesEntered() { + return false; + } @Override protected int getConcurrentTestRandomStartDelayRangeAssign() { diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/TestValidityRecomputeTask.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/TestValidityRecomputeTask.java index fb7b748fbee..e55852175d1 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/TestValidityRecomputeTask.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/TestValidityRecomputeTask.java @@ -124,7 +124,7 @@ public void test100ImportValidityScannerTask() throws Exception { // THEN TestUtil.displayThen(TEST_NAME); XMLGregorianCalendar endCal = clock.currentTimeXMLGregorianCalendar(); - assertLastRecomputeTimestamp(TASK_VALIDITY_SCANNER_OID, startCal, endCal); + assertLastScanTimestamp(TASK_VALIDITY_SCANNER_OID, startCal, endCal); PrismObject userHermanAfter = getUser(USER_HERMAN_OID); assertEffectiveActivation(userHermanAfter, ActivationStatusType.ENABLED); @@ -1488,7 +1488,7 @@ public void test190HermanGoesInvalid() throws Exception { assertEffectiveActivation(userHermanAfter, ActivationStatusType.DISABLED); assertValidityStatus(userHermanAfter, TimeIntervalStatusType.AFTER); - assertLastRecomputeTimestamp(TASK_VALIDITY_SCANNER_OID, startCal, endCal); + assertLastScanTimestamp(TASK_VALIDITY_SCANNER_OID, startCal, endCal); } @Test @@ -1512,7 +1512,7 @@ public void test200ImportTriggerScannerTask() throws Exception { // THEN TestUtil.displayThen(TEST_NAME); XMLGregorianCalendar endCal = clock.currentTimeXMLGregorianCalendar(); - assertLastRecomputeTimestamp(TASK_TRIGGER_SCANNER_OID, startCal, endCal); + assertLastScanTimestamp(TASK_TRIGGER_SCANNER_OID, startCal, endCal); } diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/util/MockTriggerHandler.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/util/MockTriggerHandler.java index a8ae0f8aa9f..61bfa7c7f2a 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/util/MockTriggerHandler.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/util/MockTriggerHandler.java @@ -26,6 +26,8 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; import com.evolveum.midpoint.xml.ns._public.common.common_3.TriggerType; +import java.util.concurrent.atomic.AtomicInteger; + /** * @author Radovan Semancik * @@ -37,14 +39,23 @@ public class MockTriggerHandler implements TriggerHandler { protected static final Trace LOGGER = TraceManager.getTrace(MockTriggerHandler.class); private PrismObject lastObject; - private int invocationCount; + private AtomicInteger invocationCount = new AtomicInteger(0); + private long delay; public PrismObject getLastObject() { return lastObject; } public int getInvocationCount() { - return invocationCount; + return invocationCount.get(); + } + + public long getDelay() { + return delay; + } + + public void setDelay(long delay) { + this.delay = delay; } /* (non-Javadoc) @@ -54,12 +65,21 @@ public int getInvocationCount() { public void handle(PrismObject object, TriggerType trigger, Task task, OperationResult result) { IntegrationTestTools.display("Mock trigger handler called with " + object); lastObject = object.clone(); - invocationCount++; + invocationCount.incrementAndGet(); + long start = System.currentTimeMillis(); + while (System.currentTimeMillis() - start < delay && task.canRun()) { + try { + Thread.sleep(500); + } catch (InterruptedException e) { + // just ignore + } + } } public void reset() { lastObject = null; - invocationCount = 0; + invocationCount.set(0); + delay = 0; } } diff --git a/model/model-intest/src/test/resources/logback-test.xml b/model/model-intest/src/test/resources/logback-test.xml index 998c2d5fc39..f47a0751808 100644 --- a/model/model-intest/src/test/resources/logback-test.xml +++ b/model/model-intest/src/test/resources/logback-test.xml @@ -80,7 +80,7 @@ - + @@ -117,7 +117,7 @@ - + diff --git a/model/model-intest/src/test/resources/manual/resource-manual-capabilities.xml b/model/model-intest/src/test/resources/manual/resource-manual-capabilities.xml new file mode 100644 index 00000000000..88bb13be3ce --- /dev/null +++ b/model/model-intest/src/test/resources/manual/resource-manual-capabilities.xml @@ -0,0 +1,171 @@ + + + + + + Manual Resource + + + + + c:connectorType + ManualConnector + + + + + + administrator + + + + + + + + + + + + + + tns:username + tns:username + tns:username + + + + + + + + + Username + 110 + + + + + + + 200 + + + + + + + + + + + + + + + account + default + true + ri:AccountObjectClass + + ri:username + + strong + + name + + + + + ri:fullname + + + fullName + + + + + + + + + + + + + + + + + + + + + + + + + true + + + true + + + true + + + + true + + + + + + + + + + + + ri:status + 1 + 0 + + + + + + + light + PT15M + + + diff --git a/model/model-intest/src/test/resources/manual/resource-semi-manual-disable.xml b/model/model-intest/src/test/resources/manual/resource-semi-manual-disable.xml index e105dc8cb7b..2e552b48734 100644 --- a/model/model-intest/src/test/resources/manual/resource-semi-manual-disable.xml +++ b/model/model-intest/src/test/resources/manual/resource-semi-manual-disable.xml @@ -157,6 +157,30 @@ + + + + true + + + true + + + true + + + + true + + + + + + + + diff --git a/model/model-intest/testng-integration.xml b/model/model-intest/testng-integration.xml index 48058754832..653db2ff587 100644 --- a/model/model-intest/testng-integration.xml +++ b/model/model-intest/testng-integration.xml @@ -126,6 +126,7 @@ + diff --git a/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java b/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java index 58736dffdbc..b5a0e1818e8 100644 --- a/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java +++ b/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java @@ -3242,7 +3242,7 @@ protected void addTrigger(String oid, XMLGregorianCalendar timestamp, String uri } protected void addTriggers(String oid, Collection timestamps, String uri) throws SchemaException, ObjectAlreadyExistsException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException, PolicyViolationException, SecurityViolationException { - Task task = taskManager.createTaskInstance(AbstractModelIntegrationTest.class.getName() + ".addTrigger"); + Task task = taskManager.createTaskInstance(AbstractModelIntegrationTest.class.getName() + ".addTriggers"); OperationResult result = task.getResult(); Collection triggers = timestamps.stream() .map(ts -> new TriggerType().timestamp(ts).handlerUri(uri)) @@ -3255,6 +3255,20 @@ protected void addTriggers(String oid, Collection timestam TestUtil.assertSuccess(result); } + protected void replaceTriggers(String oid, Collection timestamps, String uri) throws SchemaException, ObjectAlreadyExistsException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException, PolicyViolationException, SecurityViolationException { + Task task = taskManager.createTaskInstance(AbstractModelIntegrationTest.class.getName() + ".replaceTriggers"); + OperationResult result = task.getResult(); + Collection triggers = timestamps.stream() + .map(ts -> new TriggerType().timestamp(ts).handlerUri(uri)) + .collect(Collectors.toList()); + ObjectDelta delta = DeltaBuilder.deltaFor(ObjectType.class, prismContext) + .item(ObjectType.F_TRIGGER).replaceRealValues(triggers) + .asObjectDeltaCast(oid); + modelService.executeChanges(MiscSchemaUtil.createCollection(delta), null, task, result); + result.computeStatus(); + TestUtil.assertSuccess(result); + } + protected void assertTrigger(PrismObject object, String handlerUri, XMLGregorianCalendar start, XMLGregorianCalendar end) throws ObjectNotFoundException, SchemaException { for (TriggerType trigger: object.asObjectable().getTrigger()) { if (handlerUri.equals(trigger.getHandlerUri()) diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceManager.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceManager.java index 9d3c00b0052..144f6a0b0be 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceManager.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceManager.java @@ -398,6 +398,20 @@ private void completeSchemaAndCapabilities(PrismObject resource, R // We have successfully fetched the resource schema. Therefore the resource must be up. modifications.add(createResourceAvailabilityStatusDelta(resource, AvailabilityStatusType.UP)); + + } else { + if (resourceSchema != null) { + CachingMetadataType schemaCachingMetadata = resource.asObjectable().getSchema().getCachingMetadata(); + if (schemaCachingMetadata == null) { + schemaCachingMetadata = MiscSchemaUtil.generateCachingMetadata(); + modifications.add( + PropertyDelta.createModificationReplaceProperty( + new ItemPath(ResourceType.F_SCHEMA, CapabilitiesType.F_CACHING_METADATA), + resource.getDefinition(), + schemaCachingMetadata) + ); + } + } } if (!modifications.isEmpty()) { @@ -406,6 +420,7 @@ private void completeSchemaAndCapabilities(PrismObject resource, R LOGGER.trace("Completing {}:\n{}", resource, DebugUtil.debugDump(modifications, 1)); } repositoryService.modifyObject(ResourceType.class, resource.getOid(), modifications, result); + InternalMonitor.recordCount(InternalCounters.RESOURCE_REPOSITORY_MODIFY_COUNT); } catch (ObjectAlreadyExistsException ex) { // This should not happen throw new SystemException(ex); @@ -445,8 +460,20 @@ private void completeConnectorCapabilities(ConnectorSpec connectorSpec, Capabili Collection retrievedCapabilities, Collection> modifications, OperationResult result) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException { - if (!forceRefresh && capType.getNative() != null && !capType.getNative().getAny().isEmpty()) { - return; + if (capType.getNative() != null && !capType.getNative().getAny().isEmpty()) { + if (!forceRefresh) { + CachingMetadataType cachingMetadata = capType.getCachingMetadata(); + if (cachingMetadata == null) { + cachingMetadata = MiscSchemaUtil.generateCachingMetadata(); + modifications.add( + PropertyDelta.createModificationReplaceProperty( + new ItemPath(ResourceType.F_CAPABILITIES, CapabilitiesType.F_CACHING_METADATA), + connectorSpec.getResource().getDefinition(), + cachingMetadata) + ); + } + return; + } } if (retrievedCapabilities == null) { @@ -474,15 +501,11 @@ private void completeConnectorCapabilities(ConnectorSpec connectorSpec, Capabili itemPath, prismContext, capType.asPrismContainerValue().clone()); modifications.addAll(capabilitiesReplaceDelta.getModifications()); - } private ContainerDelta createSchemaUpdateDelta(PrismObject resource, ResourceSchema resourceSchema) throws SchemaException { Document xsdDoc = null; try { - // Convert to XSD - LOGGER.trace("Serializing XSD resource schema for {} to DOM", resource); - xsdDoc = resourceSchema.serializeToXsd(); if (LOGGER.isTraceEnabled()) { @@ -501,10 +524,6 @@ private ContainerDelta createSchemaUpdateDelta(PrismObject schemaContainerDelta = ContainerDelta.createDelta( ResourceType.F_SCHEMA, ResourceType.class, prismContext); PrismContainerValue cval = new PrismContainerValue(prismContext); @@ -958,17 +977,20 @@ public void testConnectionConnector(ConnectorSpec connectorSpec, Map resource, AvailabilityStatusType status, OperationResult result){ + public void modifyResourceAvailabilityStatus(PrismObject resource, AvailabilityStatusType newStatus, OperationResult result){ ResourceType resourceType = resource.asObjectable(); synchronized (resource) { - if (resourceType.getOperationalState() == null || resourceType.getOperationalState().getLastAvailabilityStatus() == null || resourceType.getOperationalState().getLastAvailabilityStatus() != status) { + AvailabilityStatusType currentStatus = ResourceTypeUtil.getLastAvailabilityStatus(resourceType); + if (!newStatus.equals(currentStatus)) { + LOGGER.debug("Changing availability status of {}: {} -> {}", resource, currentStatus, newStatus); List> modifications = new ArrayList<>(); - PropertyDelta statusDelta = createResourceAvailabilityStatusDelta(resource, status); + PropertyDelta statusDelta = createResourceAvailabilityStatusDelta(resource, newStatus); modifications.add(statusDelta); try { repositoryService.modifyObject(ResourceType.class, resourceType.getOid(), modifications, result); + InternalMonitor.recordCount(InternalCounters.RESOURCE_REPOSITORY_MODIFY_COUNT); } catch(SchemaException | ObjectAlreadyExistsException | ObjectNotFoundException ex) { throw new SystemException(ex); } @@ -976,10 +998,10 @@ public void modifyResourceAvailabilityStatus(PrismObject resource, resource.modifyUnfrozen(() -> { if (resourceType.getOperationalState() == null) { OperationalStateType operationalState = new OperationalStateType(); - operationalState.setLastAvailabilityStatus(status); + operationalState.setLastAvailabilityStatus(newStatus); resourceType.setOperationalState(operationalState); } else { - resourceType.getOperationalState().setLastAvailabilityStatus(status); + resourceType.getOperationalState().setLastAvailabilityStatus(newStatus); } }); } diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/AbstractProvisioningIntegrationTest.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/AbstractProvisioningIntegrationTest.java index e5fd4be46a0..5bcf862dab4 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/AbstractProvisioningIntegrationTest.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/AbstractProvisioningIntegrationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2017 Evolveum + * 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. @@ -19,20 +19,46 @@ */ package com.evolveum.midpoint.provisioning.impl; +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertTrue; + import java.io.File; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.ContextConfiguration; +import org.testng.AssertJUnit; +import org.w3c.dom.Element; +import com.evolveum.midpoint.common.refinery.RefinedResourceSchema; +import com.evolveum.midpoint.prism.PrismContext; +import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.provisioning.api.ProvisioningService; +import com.evolveum.midpoint.provisioning.impl.dummy.TestDummyResourceAndSchemaCaching; import com.evolveum.midpoint.provisioning.impl.mock.SynchornizationServiceMock; +import com.evolveum.midpoint.provisioning.ucf.api.ConnectorInstance; +import com.evolveum.midpoint.schema.internals.InternalCounters; +import com.evolveum.midpoint.schema.internals.InternalMonitor; import com.evolveum.midpoint.schema.internals.InternalsConfig; +import com.evolveum.midpoint.schema.processor.ResourceSchema; +import com.evolveum.midpoint.schema.processor.ResourceSchemaImpl; import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.schema.util.ObjectTypeUtil; +import com.evolveum.midpoint.schema.util.ResourceTypeUtil; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.test.AbstractIntegrationTest; +import com.evolveum.midpoint.util.exception.CommunicationException; +import com.evolveum.midpoint.util.exception.ConfigurationException; +import com.evolveum.midpoint.util.exception.ObjectNotFoundException; +import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.xml.ns._public.common.common_3.CachingMetadataType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.XmlSchemaType; +import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.ReadCapabilityType; /** * @author Radovan Semancik @@ -47,16 +73,164 @@ public abstract class AbstractProvisioningIntegrationTest extends AbstractIntegr private static final Trace LOGGER = TraceManager.getTrace(AbstractProvisioningIntegrationTest.class); - @Autowired(required=true) - protected ProvisioningService provisioningService; + @Autowired protected ProvisioningService provisioningService; + @Autowired protected SynchornizationServiceMock syncServiceMock; + + // Testing connector discovery + @Autowired protected ConnectorManager connectorManager; + + // Used to make sure that the connector is cached + @Autowired protected ResourceManager resourceManager; + + // Values used to check if something is unchanged or changed properly + private Long lastResourceVersion = null; + private ConnectorInstance lastConfiguredConnectorInstance; + private CachingMetadataType lastCachingMetadata; + private ResourceSchema lastResourceSchema = null; + private RefinedResourceSchema lastRefinedResourceSchema; - @Autowired(required = true) - protected SynchornizationServiceMock syncServiceMock; @Override public void initSystem(Task initTask, OperationResult initResult) throws Exception { InternalsConfig.encryptionChecks = false; provisioningService.postInit(initResult); } + + protected void assertVersion(PrismObject object, String expectedVersion) { + assertEquals("Wrong version of "+object, expectedVersion, object.asObjectable().getVersion()); + } + + protected void rememberResourceVersion(String version) { + lastResourceVersion = parseVersion(version); + } + + protected void assertResourceVersionIncrement(PrismObject resource, int expectedIncrement) { + assertResourceVersionIncrement(resource.getVersion(), expectedIncrement); + } + + protected void assertResourceVersionIncrement(String currentVersion, int expectedIncrement) { + long currentVersionLong = parseVersion(currentVersion); + long actualIncrement = currentVersionLong - lastResourceVersion; + assertEquals("Unexpected increment in resource version", (long)expectedIncrement, actualIncrement); + lastResourceVersion = currentVersionLong; + } + + private long parseVersion(String stringVersion) { + if (stringVersion == null) { + AssertJUnit.fail("Version is null"); + } + if (stringVersion.isEmpty()) { + AssertJUnit.fail("Version is empty"); + } + return Long.parseLong(stringVersion); + } + + protected CachingMetadataType getSchemaCachingMetadata(PrismObject resource) { + ResourceType resourceType = resource.asObjectable(); + XmlSchemaType xmlSchemaType = resourceType.getSchema(); + assertNotNull("No schema", xmlSchemaType); + Element resourceXsdSchemaElementAfter = ResourceTypeUtil.getResourceXsdSchema(resourceType); + assertNotNull("No schema XSD element", resourceXsdSchemaElementAfter); + return xmlSchemaType.getCachingMetadata(); + } + + protected void rememberSchemaMetadata(PrismObject resource) { + lastCachingMetadata = getSchemaCachingMetadata(resource); + } + + protected void assertSchemaMetadataUnchanged(PrismObject resource) { + CachingMetadataType current = getSchemaCachingMetadata(resource); + assertEquals("Schema caching metadata changed", lastCachingMetadata, current); + } + protected void rememberResourceSchema(ResourceSchema resourceSchema) { + lastResourceSchema = resourceSchema; + } + + protected void assertResourceSchemaUnchanged(ResourceSchema currentResourceSchema) { + // We really want == there. We want to make sure that this is actually the same instance and that + // it was properly cached + assertTrue("Resource schema has changed", lastResourceSchema == currentResourceSchema); + } + + protected void rememberRefinedResourceSchema(RefinedResourceSchema rResourceSchema) { + lastRefinedResourceSchema = rResourceSchema; + } + + protected void assertRefinedResourceSchemaUnchanged(RefinedResourceSchema currentRefinedResourceSchema) { + // We really want == there. We want to make sure that this is actually the same instance and that + // it was properly cached + assertTrue("Refined resource schema has changed", lastRefinedResourceSchema == currentRefinedResourceSchema); + } + + protected void assertHasSchema(PrismObject resource, String desc) throws SchemaException { + ResourceType resourceType = resource.asObjectable(); + display("Resource "+desc, resourceType); + + XmlSchemaType xmlSchemaTypeAfter = resourceType.getSchema(); + assertNotNull("No schema in "+desc, xmlSchemaTypeAfter); + Element resourceXsdSchemaElementAfter = ResourceTypeUtil.getResourceXsdSchema(resourceType); + assertNotNull("No schema XSD element in "+desc, resourceXsdSchemaElementAfter); + + String resourceXml = prismContext.serializeObjectToString(resource, PrismContext.LANG_XML); +// display("Resource XML", resourceXml); + + CachingMetadataType cachingMetadata = xmlSchemaTypeAfter.getCachingMetadata(); + assertNotNull("No caching metadata in "+desc, cachingMetadata); + assertNotNull("No retrievalTimestamp in "+desc, cachingMetadata.getRetrievalTimestamp()); + assertNotNull("No serialNumber in "+desc, cachingMetadata.getSerialNumber()); + + Element xsdElement = ObjectTypeUtil.findXsdElement(xmlSchemaTypeAfter); + ResourceSchema parsedSchema = ResourceSchemaImpl.parse(xsdElement, resource.toString(), prismContext); + assertNotNull("No schema after parsing in "+desc, parsedSchema); + } + + protected void rememberConnectorInstance(PrismObject resource) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException { + OperationResult result = new OperationResult(TestDummyResourceAndSchemaCaching.class.getName() + + ".rememberConnectorInstance"); + rememberConnectorInstance(resourceManager.getConfiguredConnectorInstance(resource, ReadCapabilityType.class, false, result)); + } + + protected void rememberConnectorInstance(ConnectorInstance currentConnectorInstance) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException { + lastConfiguredConnectorInstance = currentConnectorInstance; + } + + protected void assertConnectorInstanceUnchanged(PrismObject resource) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException { + OperationResult result = new OperationResult(TestDummyResourceAndSchemaCaching.class.getName() + + ".assertConnectorInstanceUnchanged"); + ConnectorInstance currentConfiguredConnectorInstance = resourceManager.getConfiguredConnectorInstance( + resource, ReadCapabilityType.class, false, result); + assertTrue("Connector instance has changed", lastConfiguredConnectorInstance == currentConfiguredConnectorInstance); + } + + protected void assertConnectorInstanceChanged(PrismObject resource) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException { + OperationResult result = new OperationResult(TestDummyResourceAndSchemaCaching.class.getName() + + ".rememberConnectorInstance"); + ConnectorInstance currentConfiguredConnectorInstance = resourceManager.getConfiguredConnectorInstance( + resource, ReadCapabilityType.class, false, result); + assertTrue("Connector instance has NOT changed", lastConfiguredConnectorInstance != currentConfiguredConnectorInstance); + lastConfiguredConnectorInstance = currentConfiguredConnectorInstance; + } + + protected void assertSteadyResource() throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException { + assertCounterIncrement(InternalCounters.RESOURCE_SCHEMA_FETCH_COUNT, 0); + assertCounterIncrement(InternalCounters.CONNECTOR_CAPABILITIES_FETCH_COUNT, 0); + assertCounterIncrement(InternalCounters.CONNECTOR_SCHEMA_PARSE_COUNT, 0); + assertCounterIncrement(InternalCounters.CONNECTOR_INSTANCE_INITIALIZATION_COUNT, 0); + assertCounterIncrement(InternalCounters.RESOURCE_SCHEMA_PARSE_COUNT, 0); + PrismObject resource = getResource(); + if (resource != null) { + assertResourceVersionIncrement(resource, 0); + assertSchemaMetadataUnchanged(resource); + assertConnectorInstanceUnchanged(resource); + } + + display("Resource cache", InternalMonitor.getResourceCacheStats()); + // We do not assert hits, there may be a lot of them + assertResourceCacheMissesIncrement(0); + } + + protected PrismObject getResource() { + return null; + } } diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/AbstractBasicDummyTest.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/AbstractBasicDummyTest.java index ee3372a01f6..e017308b337 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/AbstractBasicDummyTest.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/AbstractBasicDummyTest.java @@ -715,11 +715,11 @@ public void test029CapabilitiesRepo() throws Exception { @Test public void test030ResourceAndConnectorCaching() throws Exception { - TestUtil.displayTestTitle("test030ResourceAndConnectorCaching"); + final String TEST_NAME = "test030ResourceAndConnectorCaching"; + displayTestTitle(TEST_NAME); // GIVEN - OperationResult result = new OperationResult(TestOpenDj.class.getName() - + ".test010ResourceAndConnectorCaching"); + OperationResult result = new OperationResult(TestOpenDj.class.getName() + "." + TEST_NAME); ConnectorInstance configuredConnectorInstance = resourceManager.getConfiguredConnectorInstance( resource, ReadCapabilityType.class, false, result); assertNotNull("No configuredConnectorInstance", configuredConnectorInstance); @@ -727,13 +727,13 @@ public void test030ResourceAndConnectorCaching() throws Exception { assertNotNull("No resource schema", resourceSchema); // WHEN + displayWhen(TEST_NAME); PrismObject resourceAgain = provisioningService.getObject(ResourceType.class, RESOURCE_DUMMY_OID, null, null, result); // THEN - result.computeStatus(); - display("getObject result", result); - TestUtil.assertSuccess(result); + displayThen(TEST_NAME); + assertSuccess(result); ResourceType resourceTypeAgain = resourceAgain.asObjectable(); assertNotNull("No connector ref", resourceTypeAgain.getConnectorRef()); @@ -777,8 +777,7 @@ public void test030ResourceAndConnectorCaching() throws Exception { assertTrue("Connector instance was not cached", configuredConnectorInstance == configuredConnectorInstanceAgain); // Check if the connector still works. - OperationResult testResult = new OperationResult(TestOpenDj.class.getName() - + ".test010ResourceAndConnectorCaching.test"); + OperationResult testResult = new OperationResult(TestOpenDj.class.getName() + "."+TEST_NAME+".test"); configuredConnectorInstanceAgain.test(testResult); testResult.computeStatus(); TestUtil.assertSuccess("Connector test failed", testResult); diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/AbstractDummyTest.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/AbstractDummyTest.java index e7b8e2a5631..3a96cfa1e32 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/AbstractDummyTest.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/AbstractDummyTest.java @@ -164,25 +164,15 @@ public abstract class AbstractDummyTest extends AbstractProvisioningIntegrationT protected String accountWillCurrentPassword = ACCOUNT_WILL_PASSWORD; - // Testing connector discovery - @Autowired(required = true) - protected ConnectorManager connectorManager; - - // Used to make sure that the connector is cached - @Autowired(required = true) - protected ResourceManager resourceManager; - @Autowired(required = true) protected ProvisioningContextFactory provisioningContextFactory; - // Values used to check if something is unchanged or changed properly - private Long lastResourceVersion = null; - private ConnectorInstance lastConfiguredConnectorInstance; - private CachingMetadataType lastCachingMetadata; - private ResourceSchema lastResourceSchema = null; - private RefinedResourceSchema lastRefinedResourceSchema; - protected String daemonIcfUid; + + @Override + protected PrismObject getResource() { + return resource; + } @Override public void initSystem(Task initTask, OperationResult initResult) throws Exception { @@ -425,135 +415,4 @@ protected void assertEntitlementPriv(PrismObject account, String ent assertAssociation(account, ASSOCIATION_PRIV_NAME, entitlementOid); } - protected void assertVersion(PrismObject object, String expectedVersion) { - assertEquals("Wrong version of "+object, expectedVersion, object.asObjectable().getVersion()); - } - - protected void rememberResourceVersion(String version) { - lastResourceVersion = parseVersion(version); - } - - protected void assertResourceVersionIncrement(PrismObject resource, int expectedIncrement) { - assertResourceVersionIncrement(resource.getVersion(), expectedIncrement); - } - - protected void assertResourceVersionIncrement(String currentVersion, int expectedIncrement) { - long currentVersionLong = parseVersion(currentVersion); - long actualIncrement = currentVersionLong - lastResourceVersion; - assertEquals("Unexpected increment in resource version", (long)expectedIncrement, actualIncrement); - lastResourceVersion = currentVersionLong; - } - - private long parseVersion(String stringVersion) { - if (stringVersion == null) { - AssertJUnit.fail("Version is null"); - } - if (stringVersion.isEmpty()) { - AssertJUnit.fail("Version is empty"); - } - return Long.parseLong(stringVersion); - } - - protected CachingMetadataType getSchemaCachingMetadata(PrismObject resource) { - ResourceType resourceType = resource.asObjectable(); - XmlSchemaType xmlSchemaTypeAfter = resourceType.getSchema(); - assertNotNull("No schema", xmlSchemaTypeAfter); - Element resourceXsdSchemaElementAfter = ResourceTypeUtil.getResourceXsdSchema(resourceType); - assertNotNull("No schema XSD element", resourceXsdSchemaElementAfter); - return xmlSchemaTypeAfter.getCachingMetadata(); - } - - protected void rememberSchemaMetadata(PrismObject resource) { - lastCachingMetadata = getSchemaCachingMetadata(resource); - } - - protected void assertSchemaMetadataUnchanged(PrismObject resource) { - CachingMetadataType current = getSchemaCachingMetadata(resource); - assertEquals("Schema caching metadata changed", lastCachingMetadata, current); - } - - protected void rememberResourceSchema(ResourceSchema resourceSchema) { - lastResourceSchema = resourceSchema; - } - - protected void assertResourceSchemaUnchanged(ResourceSchema currentResourceSchema) { - // We really want == there. We want to make sure that this is actually the same instance and that - // it was properly cached - assertTrue("Resource schema has changed", lastResourceSchema == currentResourceSchema); - } - - protected void rememberRefinedResourceSchema(RefinedResourceSchema rResourceSchema) { - lastRefinedResourceSchema = rResourceSchema; - } - - protected void assertRefinedResourceSchemaUnchanged(RefinedResourceSchema currentRefinedResourceSchema) { - // We really want == there. We want to make sure that this is actually the same instance and that - // it was properly cached - assertTrue("Refined resource schema has changed", lastRefinedResourceSchema == currentRefinedResourceSchema); - } - - protected void assertHasSchema(PrismObject resource, String desc) throws SchemaException { - ResourceType resourceType = resource.asObjectable(); - display("Resource "+desc, resourceType); - - XmlSchemaType xmlSchemaTypeAfter = resourceType.getSchema(); - assertNotNull("No schema in "+desc, xmlSchemaTypeAfter); - Element resourceXsdSchemaElementAfter = ResourceTypeUtil.getResourceXsdSchema(resourceType); - assertNotNull("No schema XSD element in "+desc, resourceXsdSchemaElementAfter); - - String resourceXml = prismContext.serializeObjectToString(resource, PrismContext.LANG_XML); -// display("Resource XML", resourceXml); - - CachingMetadataType cachingMetadata = xmlSchemaTypeAfter.getCachingMetadata(); - assertNotNull("No caching metadata in "+desc, cachingMetadata); - assertNotNull("No retrievalTimestamp in "+desc, cachingMetadata.getRetrievalTimestamp()); - assertNotNull("No serialNumber in "+desc, cachingMetadata.getSerialNumber()); - - Element xsdElement = ObjectTypeUtil.findXsdElement(xmlSchemaTypeAfter); - ResourceSchema parsedSchema = ResourceSchemaImpl.parse(xsdElement, resource.toString(), prismContext); - assertNotNull("No schema after parsing in "+desc, parsedSchema); - } - - protected void rememberConnectorInstance(PrismObject resource) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException { - OperationResult result = new OperationResult(TestDummyResourceAndSchemaCaching.class.getName() - + ".rememberConnectorInstance"); - rememberConnectorInstance(resourceManager.getConfiguredConnectorInstance(resource, ReadCapabilityType.class, false, result)); - } - - protected void rememberConnectorInstance(ConnectorInstance currentConnectorInstance) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException { - lastConfiguredConnectorInstance = currentConnectorInstance; - } - - protected void assertConnectorInstanceUnchanged(PrismObject resource) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException { - OperationResult result = new OperationResult(TestDummyResourceAndSchemaCaching.class.getName() - + ".rememberConnectorInstance"); - ConnectorInstance currentConfiguredConnectorInstance = resourceManager.getConfiguredConnectorInstance( - resource, ReadCapabilityType.class, false, result); - assertTrue("Connector instance has changed", lastConfiguredConnectorInstance == currentConfiguredConnectorInstance); - } - - protected void assertConnectorInstanceChanged(PrismObject resource) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException { - OperationResult result = new OperationResult(TestDummyResourceAndSchemaCaching.class.getName() - + ".rememberConnectorInstance"); - ConnectorInstance currentConfiguredConnectorInstance = resourceManager.getConfiguredConnectorInstance( - resource, ReadCapabilityType.class, false, result); - assertTrue("Connector instance has NOT changed", lastConfiguredConnectorInstance != currentConfiguredConnectorInstance); - lastConfiguredConnectorInstance = currentConfiguredConnectorInstance; - } - - protected void assertSteadyResource() throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException { - assertCounterIncrement(InternalCounters.RESOURCE_SCHEMA_FETCH_COUNT, 0); - assertCounterIncrement(InternalCounters.CONNECTOR_CAPABILITIES_FETCH_COUNT, 0); - assertCounterIncrement(InternalCounters.CONNECTOR_SCHEMA_PARSE_COUNT, 0); - assertCounterIncrement(InternalCounters.CONNECTOR_INSTANCE_INITIALIZATION_COUNT, 0); - assertCounterIncrement(InternalCounters.RESOURCE_SCHEMA_PARSE_COUNT, 0); - assertResourceVersionIncrement(resource, 0); - assertSchemaMetadataUnchanged(resource); - assertConnectorInstanceUnchanged(resource); - - display("Resource cache", InternalMonitor.getResourceCacheStats()); - // We do not assert hits, there may be a lot of them - assertResourceCacheMissesIncrement(0); - } - } diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummySchemaless.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummySchemaless.java index 7f8198a5152..32c65673f6f 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummySchemaless.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummySchemaless.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2017 Evolveum + * 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. @@ -26,10 +26,12 @@ import static org.testng.AssertJUnit.assertTrue; import java.io.File; +import java.util.Collection; import java.util.List; import javax.xml.namespace.QName; +import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.ContextConfiguration; @@ -39,19 +41,36 @@ import com.evolveum.icf.dummy.resource.DummyAccount; import com.evolveum.icf.dummy.resource.DummyResource; +import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition; import com.evolveum.midpoint.common.refinery.RefinedResourceSchemaImpl; +import com.evolveum.midpoint.prism.Containerable; +import com.evolveum.midpoint.prism.Definition; +import com.evolveum.midpoint.prism.PrismContainer; +import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.delta.DiffUtil; +import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.prism.util.PrismAsserts; import com.evolveum.midpoint.prism.util.PrismTestUtil; +import com.evolveum.midpoint.provisioning.api.ProvisioningOperationOptions; import com.evolveum.midpoint.provisioning.api.ProvisioningService; +import com.evolveum.midpoint.provisioning.impl.AbstractProvisioningIntegrationTest; import com.evolveum.midpoint.provisioning.impl.ProvisioningTestUtil; +import com.evolveum.midpoint.provisioning.impl.opendj.TestOpenDj; +import com.evolveum.midpoint.provisioning.ucf.api.ConnectorInstance; import com.evolveum.midpoint.schema.CapabilityUtil; import com.evolveum.midpoint.schema.constants.ConnectorTestOperation; import com.evolveum.midpoint.schema.constants.SchemaConstants; +import com.evolveum.midpoint.schema.internals.InternalCounters; import com.evolveum.midpoint.schema.internals.InternalsConfig; +import com.evolveum.midpoint.schema.processor.ObjectClassComplexTypeDefinition; +import com.evolveum.midpoint.schema.processor.ResourceAttributeDefinition; import com.evolveum.midpoint.schema.processor.ResourceSchema; +import com.evolveum.midpoint.schema.processor.ResourceSchemaImpl; import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.schema.util.ObjectTypeUtil; import com.evolveum.midpoint.schema.util.ResourceTypeUtil; +import com.evolveum.midpoint.schema.util.SchemaTestConstants; import com.evolveum.midpoint.schema.util.ShadowUtil; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.test.AbstractIntegrationTest; @@ -60,13 +79,17 @@ import com.evolveum.midpoint.test.util.TestUtil; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.xml.ns._public.common.common_3.CachingMetadataType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.CapabilitiesType; import com.evolveum.midpoint.xml.ns._public.common.common_3.CapabilityCollectionType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ConnectorType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowKindType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; import com.evolveum.midpoint.xml.ns._public.common.common_3.XmlSchemaType; import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.ActivationCapabilityType; import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.CredentialsCapabilityType; +import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.ReadCapabilityType; import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.ScriptCapabilityType; import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.TestConnectionCapabilityType; @@ -80,7 +103,7 @@ */ @ContextConfiguration(locations = "classpath:ctx-provisioning-test-main.xml") @DirtiesContext -public class TestDummySchemaless extends AbstractIntegrationTest { +public class TestDummySchemaless extends AbstractProvisioningIntegrationTest { private static final File TEST_DIR = new File(AbstractDummyTest.TEST_DIR_DUMMY, "dummy-schemaless"); @@ -103,7 +126,6 @@ public class TestDummySchemaless extends AbstractIntegrationTest { private static DummyResource dummyResourceSchemaless; private PrismObject resourceStaticSchema; - private ResourceType resourceTypeStaticSchema; private static DummyResource dummyResourceStaticSchema; private static DummyResourceContoller dummyResourceSchemalessCtl; @@ -134,13 +156,17 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti dummyResourceSchemaless = dummyResourceSchemalessCtl.getDummyResource(); resourceStaticSchema = addResourceFromFile(RESOURCE_DUMMY_STATIC_SCHEMA_FILE, IntegrationTestTools.DUMMY_CONNECTOR_TYPE, initResult); - resourceTypeStaticSchema = resourceStaticSchema.asObjectable(); dummyResourceStaticSchema = DummyResource.getInstance(RESOURCE_DUMMY_STATIC_SCHEMA_INSTANCE_ID); dummyResourceStaticSchema.reset(); dummyResourceStaticSchema.populateWithDefaultSchema(); } + + @Override + protected PrismObject getResource() { + return resourceStaticSchema; + } @Test public void test000Integrity() throws Exception { @@ -249,7 +275,242 @@ public void test006GetObjectSchemaless() throws Exception { assertNotNull("No connector ref", resourceType.getConnectorRef()); assertNotNull("No connector ref OID", resourceType.getConnectorRef().getOid()); } + + @Test + public void test020ResourceStaticSchemaTest() throws Exception { + resourceStaticSchemaTest("test020ResourceStaticSchemaTest"); + } + + public void resourceStaticSchemaTest(final String TEST_NAME) throws Exception { + displayTestTitle(TEST_NAME); + // GIVEN + Task task = createTask(TEST_NAME); + OperationResult result = task.getResult(); + + // Some connector initialization and other things might happen in previous tests. + // The monitor is static, not part of spring context, it will not be cleared + + rememberCounter(InternalCounters.RESOURCE_SCHEMA_FETCH_COUNT); + rememberCounter(InternalCounters.CONNECTOR_SCHEMA_PARSE_COUNT); + rememberCounter(InternalCounters.CONNECTOR_CAPABILITIES_FETCH_COUNT); + rememberCounter(InternalCounters.CONNECTOR_INSTANCE_INITIALIZATION_COUNT); + rememberCounter(InternalCounters.RESOURCE_SCHEMA_PARSE_COUNT); + rememberResourceCacheStats(); + + // Check that there is no schema before test (pre-condition) + PrismObject resourceBefore = repositoryService.getObject(ResourceType.class, RESOURCE_DUMMY_STATIC_SCHEMA_OID, null, result); + ResourceType resourceTypeBefore = resourceBefore.asObjectable(); + rememberResourceVersion(resourceBefore.getVersion()); + assertNotNull("No connector ref", resourceTypeBefore.getConnectorRef()); + assertNotNull("No connector ref OID", resourceTypeBefore.getConnectorRef().getOid()); + ConnectorType connector = repositoryService.getObject(ConnectorType.class, + resourceTypeBefore.getConnectorRef().getOid(), null, result).asObjectable(); + assertNotNull(connector); + XmlSchemaType xmlSchemaTypeBefore = resourceTypeBefore.getSchema(); + assertNotNull("No schema in static resource before", xmlSchemaTypeBefore); + Element resourceXsdSchemaElementBefore = ResourceTypeUtil.getResourceXsdSchema(resourceTypeBefore); + assertNotNull("No schema XSD element in static resource before", resourceXsdSchemaElementBefore); + + // WHEN + OperationResult testResult = provisioningService.testResource(RESOURCE_DUMMY_STATIC_SCHEMA_OID, task); + + // THEN + display("Test result", testResult); + OperationResult connectorResult = assertSingleConnectorTestResult(testResult); + assertTestResourceSuccess(connectorResult, ConnectorTestOperation.CONNECTOR_INITIALIZATION); + assertTestResourceSuccess(connectorResult, ConnectorTestOperation.CONNECTOR_CONFIGURATION); + assertTestResourceSuccess(connectorResult, ConnectorTestOperation.CONNECTOR_CONNECTION); + assertTestResourceSuccess(connectorResult, ConnectorTestOperation.CONNECTOR_CAPABILITIES); + assertSuccess(connectorResult); + assertTestResourceSuccess(testResult, ConnectorTestOperation.RESOURCE_SCHEMA); + assertSuccess(testResult); + + PrismObject resourceRepoAfter = repositoryService.getObject(ResourceType.class, + RESOURCE_DUMMY_STATIC_SCHEMA_OID, null, result); + ResourceType resourceTypeRepoAfter = resourceRepoAfter.asObjectable(); + display("Resource after test", resourceTypeRepoAfter); + + XmlSchemaType xmlSchemaTypeAfter = resourceTypeRepoAfter.getSchema(); + assertNotNull("No schema after test connection", xmlSchemaTypeAfter); + Element resourceXsdSchemaElementAfter = ResourceTypeUtil.getResourceXsdSchema(resourceTypeRepoAfter); + assertNotNull("No schema after test connection", resourceXsdSchemaElementAfter); + + IntegrationTestTools.displayXml("Resource XML", resourceRepoAfter); + + CachingMetadataType cachingMetadata = xmlSchemaTypeAfter.getCachingMetadata(); + assertNotNull("No caching metadata", cachingMetadata); + assertNotNull("No retrievalTimestamp", cachingMetadata.getRetrievalTimestamp()); + assertNotNull("No serialNumber", cachingMetadata.getSerialNumber()); + + Element xsdElement = ObjectTypeUtil.findXsdElement(xmlSchemaTypeAfter); + ResourceSchema parsedSchema = ResourceSchemaImpl.parse(xsdElement, resourceTypeBefore.toString(), prismContext); + assertNotNull("No schema after parsing", parsedSchema); + + // schema will be checked in next test + + assertCounterIncrement(InternalCounters.RESOURCE_SCHEMA_FETCH_COUNT, 1); + assertCounterIncrement(InternalCounters.CONNECTOR_SCHEMA_PARSE_COUNT, 0); + assertCounterIncrement(InternalCounters.CONNECTOR_CAPABILITIES_FETCH_COUNT, 1); + assertCounterIncrement(InternalCounters.CONNECTOR_INSTANCE_INITIALIZATION_COUNT, 1); + + // Not sure why 2 instead 1, but this is a small difference, we can live with that + assertCounterIncrement(InternalCounters.RESOURCE_SCHEMA_PARSE_COUNT, 2); + + // One increment for availablity status, the other for schema + assertResourceVersionIncrement(resourceRepoAfter, 2); + + } + /** + * MID-4472, MID-4174 + */ + @Test + public void test030ResourceStatciSchemaResourceAndConnectorCaching() throws Exception { + resourceStatciSchemaResourceAndConnectorCaching("test030ResourceStatciSchemaResourceAndConnectorCaching"); + } + + public void resourceStatciSchemaResourceAndConnectorCaching(final String TEST_NAME) throws Exception { + displayTestTitle(TEST_NAME); + + // GIVEN + OperationResult result = new OperationResult(TestOpenDj.class.getName() + "." + TEST_NAME); + + // re-read the resource before tests so we have a clean slate, e.g. configuration properly parsed (no raw elements) + resourceStaticSchema = provisioningService.getObject(ResourceType.class, RESOURCE_DUMMY_STATIC_SCHEMA_OID, null, null, result); + ConnectorInstance currentConnectorInstance = resourceManager.getConfiguredConnectorInstance( + resourceStaticSchema, ReadCapabilityType.class, false, result); + + IntegrationTestTools.displayXml("Initialized static schema resource", resourceStaticSchema); + + rememberCounter(InternalCounters.RESOURCE_SCHEMA_FETCH_COUNT); + rememberCounter(InternalCounters.CONNECTOR_SCHEMA_PARSE_COUNT); + rememberCounter(InternalCounters.CONNECTOR_CAPABILITIES_FETCH_COUNT); + rememberCounter(InternalCounters.CONNECTOR_INSTANCE_INITIALIZATION_COUNT); + rememberCounter(InternalCounters.RESOURCE_SCHEMA_PARSE_COUNT); + rememberSchemaMetadata(resourceStaticSchema); + rememberConnectorInstance(currentConnectorInstance); + rememberResourceCacheStats(); + + ConnectorInstance configuredConnectorInstance = resourceManager.getConfiguredConnectorInstance( + resourceStaticSchema, ReadCapabilityType.class, false, result); + assertNotNull("No configuredConnectorInstance", configuredConnectorInstance); + ResourceSchema resourceSchemaBefore = RefinedResourceSchemaImpl.getResourceSchema(resourceStaticSchema, prismContext); + assertNotNull("No resource schema", resourceSchemaBefore); + assertStaticSchemaSanity(resourceSchemaBefore); + + // WHEN + displayWhen(TEST_NAME); + PrismObject resourceAgain = provisioningService.getObject(ResourceType.class, RESOURCE_DUMMY_STATIC_SCHEMA_OID, + null, null, result); + + // THEN + displayThen(TEST_NAME); + assertSuccess(result); + + ResourceType resourceTypeAgain = resourceAgain.asObjectable(); + assertNotNull("No connector ref", resourceTypeAgain.getConnectorRef()); + assertNotNull("No connector ref OID", resourceTypeAgain.getConnectorRef().getOid()); + + PrismContainer configurationContainer = resourceStaticSchema.findContainer(ResourceType.F_CONNECTOR_CONFIGURATION); + PrismContainer configurationContainerAgain = resourceAgain + .findContainer(ResourceType.F_CONNECTOR_CONFIGURATION); + assertTrue("Configurations not equivalent", configurationContainer.equivalent(configurationContainerAgain)); + + // Check resource schema caching + ResourceSchema resourceSchemaAgain = RefinedResourceSchemaImpl.getResourceSchema(resourceAgain, prismContext); + assertNotNull("No resource schema (again)", resourceSchemaAgain); + assertTrue("Resource schema was not cached", resourceSchemaBefore == resourceSchemaAgain); + + // Check capabilities caching + + CapabilitiesType capabilitiesType = resourceStaticSchema.asObjectable().getCapabilities(); + assertNotNull("No capabilities fetched from provisioning", capabilitiesType); + CachingMetadataType capCachingMetadataType = capabilitiesType.getCachingMetadata(); + assertNotNull("No capabilities caching metadata fetched from provisioning", capCachingMetadataType); + CachingMetadataType capCachingMetadataTypeAgain = resourceTypeAgain.getCapabilities().getCachingMetadata(); + assertEquals("Capabilities caching metadata serial number has changed", capCachingMetadataType.getSerialNumber(), + capCachingMetadataTypeAgain.getSerialNumber()); + assertEquals("Capabilities caching metadata timestamp has changed", capCachingMetadataType.getRetrievalTimestamp(), + capCachingMetadataTypeAgain.getRetrievalTimestamp()); + + // Rough test if everything is fine + resourceStaticSchema.asObjectable().setFetchResult(null); + resourceAgain.asObjectable().setFetchResult(null); + ObjectDelta dummyResourceDiff = DiffUtil.diff(resourceStaticSchema, resourceAgain); + display("Dummy resource diff", dummyResourceDiff); + assertTrue("The resource read again is not the same as the original. diff:"+dummyResourceDiff, dummyResourceDiff.isEmpty()); + + // Now we stick our nose deep inside the provisioning impl. But we need + // to make sure that the + // configured connector is properly cached + ConnectorInstance configuredConnectorInstanceAgain = resourceManager.getConfiguredConnectorInstance( + resourceAgain, ReadCapabilityType.class, false, result); + assertNotNull("No configuredConnectorInstance (again)", configuredConnectorInstanceAgain); + assertTrue("Connector instance was not cached", configuredConnectorInstance == configuredConnectorInstanceAgain); + + // Check if the connector still works. + OperationResult testResult = new OperationResult(TestOpenDj.class.getName() + + ".test010ResourceAndConnectorCaching.test"); + configuredConnectorInstanceAgain.test(testResult); + testResult.computeStatus(); + TestUtil.assertSuccess("Connector test failed", testResult); + + // Test connection should also refresh the connector by itself. So check if it has been refreshed + + ConnectorInstance configuredConnectorInstanceAfterTest = resourceManager.getConfiguredConnectorInstance( + resourceAgain, ReadCapabilityType.class, false, result); + assertNotNull("No configuredConnectorInstance (again)", configuredConnectorInstanceAfterTest); + assertTrue("Connector instance was not cached", configuredConnectorInstanceAgain == configuredConnectorInstanceAfterTest); + + assertSteadyResource(); + } + + @Test + public void test040ReAddResourceStaticSchema() throws Exception { + final String TEST_NAME = "test040ReAddResourceStaticSchema"; + displayTestTitle(TEST_NAME); + // GIVEN + Task task = createTask(TEST_NAME); + OperationResult result = task.getResult(); + + PrismObject resourceNew = prismContext.parseObject(RESOURCE_DUMMY_STATIC_SCHEMA_FILE); + fillInConnectorRef(resourceNew, IntegrationTestTools.DUMMY_CONNECTOR_TYPE, result); + + // WHEN + displayWhen(TEST_NAME); + provisioningService.addObject(resourceNew, null, ProvisioningOperationOptions.createOverwrite(true), task, result); + + // THEN + displayThen(TEST_NAME); + assertSuccess(result); + + assertCounterIncrement(InternalCounters.RESOURCE_SCHEMA_FETCH_COUNT, 0); + assertCounterIncrement(InternalCounters.CONNECTOR_SCHEMA_PARSE_COUNT, 0); + assertCounterIncrement(InternalCounters.CONNECTOR_CAPABILITIES_FETCH_COUNT, 0); + assertCounterIncrement(InternalCounters.CONNECTOR_INSTANCE_INITIALIZATION_COUNT, 0); + assertCounterIncrement(InternalCounters.RESOURCE_SCHEMA_PARSE_COUNT, 0); + + PrismObject resourceRepoAfter = repositoryService.getObject(ResourceType.class, + RESOURCE_DUMMY_STATIC_SCHEMA_OID, null, result); + + // One increment for availablity status, the other for schema + assertResourceVersionIncrement(resourceRepoAfter, 1); + } + + @Test + public void test042ResourceStaticSchemaTestAgain() throws Exception { + resourceStaticSchemaTest("test042ResourceStaticSchemaTestAgain"); + } + + /** + * MID-4472, MID-4174 + */ + @Test + public void test044ResourceStatciSchemaResourceAndConnectorCachingAgain() throws Exception { + resourceStatciSchemaResourceAndConnectorCaching("test044ResourceStatciSchemaResourceAndConnectorCachingAgain"); + } + + /** * This should be the very first test that works with the resource. * @@ -307,15 +568,15 @@ public void test105ParsedSchemaStaticSchema() throws Exception { // THEN // The returned type should have the schema pre-parsed - assertNotNull(RefinedResourceSchemaImpl.hasParsedSchema(resourceTypeStaticSchema)); + assertNotNull(RefinedResourceSchemaImpl.hasParsedSchema(resourceStaticSchema.asObjectable())); // Also test if the utility method returns the same thing - ResourceSchema returnedSchema = RefinedResourceSchemaImpl.getResourceSchema(resourceTypeStaticSchema, prismContext); + ResourceSchema returnedSchema = RefinedResourceSchemaImpl.getResourceSchema(resourceStaticSchema.asObjectable(), prismContext); display("Parsed resource schema", returnedSchema); assertNotNull("Null resource schema", returnedSchema); - dummyResourceSchemalessCtl.assertDummyResourceSchemaSanity(returnedSchema, resourceTypeStaticSchema, true); + assertStaticSchemaSanity(returnedSchema); } @Test @@ -336,7 +597,113 @@ public void test106GetObjectStaticSchema() throws Exception { display("Parsed resource schema", returnedSchema); assertNotNull("Null resource schema", returnedSchema); - dummyResourceSchemalessCtl.assertDummyResourceSchemaSanity(returnedSchema, resource.asObjectable(), true); + assertStaticSchemaSanity(returnedSchema); + } + + private void assertStaticSchemaSanity(ResourceSchema resorceSchema) { + ResourceType resourceType = resourceStaticSchema.asObjectable(); + assertNotNull("No resource schema in "+resourceType, resorceSchema); + QName objectClassQname = new QName(ResourceTypeUtil.getResourceNamespace(resourceType), "AccountObjectClass"); + ObjectClassComplexTypeDefinition accountDefinition = resorceSchema.findObjectClassDefinition(objectClassQname); + assertNotNull("No object class definition for "+objectClassQname+" in resource schema", accountDefinition); + ObjectClassComplexTypeDefinition accountDef1 = resorceSchema.findDefaultObjectClassDefinition(ShadowKindType.ACCOUNT); + assertTrue("Mismatched account definition: "+accountDefinition+" <-> "+accountDef1, accountDefinition == accountDef1); + + assertNotNull("No object class definition " + objectClassQname, accountDefinition); + assertEquals("Object class " + objectClassQname + " is not account", ShadowKindType.ACCOUNT, accountDefinition.getKind()); + assertTrue("Object class " + objectClassQname + " is not default account", accountDefinition.isDefaultInAKind()); + assertFalse("Object class " + objectClassQname + " is empty", accountDefinition.isEmpty()); + assertFalse("Object class " + objectClassQname + " is empty", accountDefinition.isIgnored()); + + Collection identifiers = accountDefinition.getPrimaryIdentifiers(); + assertNotNull("Null identifiers for " + objectClassQname, identifiers); + assertFalse("Empty identifiers for " + objectClassQname, identifiers.isEmpty()); + + + ResourceAttributeDefinition uidAttributeDefinition = accountDefinition.findAttributeDefinition(SchemaTestConstants.ICFS_UID); + assertNotNull("No definition for attribute "+SchemaTestConstants.ICFS_UID, uidAttributeDefinition); + assertTrue("Attribute "+SchemaTestConstants.ICFS_UID+" in not an identifier",uidAttributeDefinition.isIdentifier(accountDefinition)); + assertTrue("Attribute "+SchemaTestConstants.ICFS_UID+" in not in identifiers list",identifiers.contains(uidAttributeDefinition)); + assertEquals("Wrong displayName for attribute "+SchemaTestConstants.ICFS_UID, "Modified ConnId UID", uidAttributeDefinition.getDisplayName()); + assertEquals("Wrong displayOrder for attribute "+SchemaTestConstants.ICFS_UID, (Integer)100, uidAttributeDefinition.getDisplayOrder()); + + Collection secondaryIdentifiers = accountDefinition.getSecondaryIdentifiers(); + assertNotNull("Null secondary identifiers for " + objectClassQname, secondaryIdentifiers); + assertFalse("Empty secondary identifiers for " + objectClassQname, secondaryIdentifiers.isEmpty()); + + ResourceAttributeDefinition nameAttributeDefinition = accountDefinition.findAttributeDefinition(SchemaTestConstants.ICFS_NAME); + assertNotNull("No definition for attribute "+SchemaTestConstants.ICFS_NAME, nameAttributeDefinition); + assertTrue("Attribute "+SchemaTestConstants.ICFS_NAME+" in not an identifier",nameAttributeDefinition.isSecondaryIdentifier(accountDefinition)); + assertTrue("Attribute "+SchemaTestConstants.ICFS_NAME+" in not in identifiers list",secondaryIdentifiers.contains(nameAttributeDefinition)); + assertEquals("Wrong displayName for attribute "+SchemaTestConstants.ICFS_NAME, "Modified ConnId Name", nameAttributeDefinition.getDisplayName()); + assertEquals("Wrong displayOrder for attribute "+SchemaTestConstants.ICFS_NAME, (Integer)110, nameAttributeDefinition.getDisplayOrder()); + + assertNotNull("Null identifiers in account", accountDef1.getPrimaryIdentifiers()); + assertFalse("Empty identifiers in account", accountDef1.getPrimaryIdentifiers().isEmpty()); + assertNotNull("Null secondary identifiers in account", accountDef1.getSecondaryIdentifiers()); + assertFalse("Empty secondary identifiers in account", accountDef1.getSecondaryIdentifiers().isEmpty()); + assertNotNull("No naming attribute in account", accountDef1.getNamingAttribute()); + assertFalse("No nativeObjectClass in account", StringUtils.isEmpty(accountDef1.getNativeObjectClass())); + + ResourceAttributeDefinition uidDef = accountDef1 + .findAttributeDefinition(SchemaTestConstants.ICFS_UID); + assertEquals(1, uidDef.getMaxOccurs()); + assertEquals(0, uidDef.getMinOccurs()); + assertFalse("No UID display name", StringUtils.isBlank(uidDef.getDisplayName())); + assertFalse("UID has create", uidDef.canAdd()); + assertFalse("UID has update",uidDef.canModify()); + assertTrue("No UID read",uidDef.canRead()); + assertTrue("UID definition not in identifiers", accountDef1.getPrimaryIdentifiers().contains(uidDef)); + assertEquals("Wrong refined displayName for attribute "+SchemaTestConstants.ICFS_UID, "Modified ConnId UID", uidDef.getDisplayName()); + assertEquals("Wrong refined displayOrder for attribute "+SchemaTestConstants.ICFS_UID, (Integer)100, uidDef.getDisplayOrder()); + + ResourceAttributeDefinition nameDef = accountDef1 + .findAttributeDefinition(SchemaTestConstants.ICFS_NAME); + assertEquals(1, nameDef.getMaxOccurs()); + assertEquals(1, nameDef.getMinOccurs()); + assertFalse("No NAME displayName", StringUtils.isBlank(nameDef.getDisplayName())); + assertTrue("No NAME create", nameDef.canAdd()); + assertTrue("No NAME update",nameDef.canModify()); + assertTrue("No NAME read",nameDef.canRead()); + assertTrue("NAME definition not in identifiers", accountDef1.getSecondaryIdentifiers().contains(nameDef)); + assertEquals("Wrong refined displayName for attribute "+SchemaTestConstants.ICFS_NAME, "Modified ConnId Name", nameDef.getDisplayName()); + assertEquals("Wrong refined displayOrder for attribute "+SchemaTestConstants.ICFS_NAME, (Integer)110, nameDef.getDisplayOrder()); + + assertNull("The _PASSSWORD_ attribute sneaked into schema", accountDef1.findAttributeDefinition(new QName(SchemaTestConstants.NS_ICFS,"password"))); + + // ACCOUNT + ObjectClassComplexTypeDefinition accountDef = resorceSchema.findDefaultObjectClassDefinition(ShadowKindType.ACCOUNT); + assertNotNull("No ACCOUNT kind definition", accountDef); + + ResourceAttributeDefinition fullnameDef = accountDef.findAttributeDefinition("fullname"); + assertNotNull("No definition for fullname", fullnameDef); + assertEquals(1, fullnameDef.getMaxOccurs()); + assertEquals(1, fullnameDef.getMinOccurs()); + assertTrue("No fullname create", fullnameDef.canAdd()); + assertTrue("No fullname update", fullnameDef.canModify()); + assertTrue("No fullname read", fullnameDef.canRead()); + assertTrue("Wrong displayOrder for attribute fullName: "+fullnameDef.getDisplayOrder(), + fullnameDef.getDisplayOrder() == 200 || fullnameDef.getDisplayOrder() == 250 || fullnameDef.getDisplayOrder() == 260); + + // GROUP + ObjectClassComplexTypeDefinition groupObjectClass = resorceSchema.findObjectClassDefinition(SchemaTestConstants.GROUP_OBJECT_CLASS_LOCAL_NAME); + assertNotNull("No group objectClass", groupObjectClass); + + ResourceAttributeDefinition membersDef = groupObjectClass.findAttributeDefinition(DummyResourceContoller.DUMMY_GROUP_MEMBERS_ATTRIBUTE_NAME); + assertNotNull("No definition for members", membersDef); + assertEquals("Wrong maxOccurs", -1, membersDef.getMaxOccurs()); + assertEquals("Wrong minOccurs", 0, membersDef.getMinOccurs()); + assertTrue("No members create", membersDef.canAdd()); + assertTrue("No members update", membersDef.canModify()); + assertTrue("No members read", membersDef.canRead()); + + assertEquals("Unexpected number of schema definitions in "+dummyResourceSchemalessCtl.getName()+" dummy resource", dummyResourceStaticSchema.getNumberOfObjectclasses(), resorceSchema.getDefinitions().size()); + + for (Definition def: resorceSchema.getDefinitions()) { + if (def instanceof RefinedObjectClassDefinition) { + AssertJUnit.fail("Refined definition sneaked into resource schema of "+dummyResourceSchemalessCtl.getName()+" dummy resource: "+def); + } + } } @Test @@ -412,9 +779,7 @@ public void test200AddAccount() throws Exception { String addedObjectOid = provisioningService.addObject(account.asPrismObject(), null, null, taskManager.createTaskInstance(), result); // THEN - result.computeStatus(); - display("add object result", result); - TestUtil.assertSuccess("addObject has failed (result)", result); + assertSuccess("addObject has failed (result)", result); assertEquals(ACCOUNT_WILL_OID, addedObjectOid); account.asPrismObject().checkConsistence(); diff --git a/provisioning/provisioning-impl/src/test/resources/dummy/dummy-schemaless/resource-dummy-schemaless-static-schema.xml b/provisioning/provisioning-impl/src/test/resources/dummy/dummy-schemaless/resource-dummy-schemaless-static-schema.xml index 6f1f8d655e9..32e2cef142d 100644 --- a/provisioning/provisioning-impl/src/test/resources/dummy/dummy-schemaless/resource-dummy-schemaless-static-schema.xml +++ b/provisioning/provisioning-impl/src/test/resources/dummy/dummy-schemaless/resource-dummy-schemaless-static-schema.xml @@ -1,6 +1,6 @@ + - ConnId UID + + Modified ConnId UID 100 read @@ -88,7 +91,8 @@ - ConnId Name + + Modified ConnId Name 110 @@ -192,9 +196,29 @@ + + + + + + + + + + + + + + resource + + + connector + + + diff --git a/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/CacheRegistry.java b/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/CacheRegistry.java new file mode 100644 index 00000000000..52d9b48ee69 --- /dev/null +++ b/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/CacheRegistry.java @@ -0,0 +1,42 @@ +/* + * 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.repo.common; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.stereotype.Component; + +@Component +public class CacheRegistry { + + private List cacheableServices = new ArrayList<>(); + + public void registerCacheableService(Cacheable cacheableService) { + cacheableServices.add(cacheableService); + } + + public List getCacheableServices() { + return cacheableServices; + } + + public void clearAllCaches() { + for (Cacheable cacheableService : cacheableServices) { + cacheableService.clearCache(); + } + } +} + diff --git a/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/Cacheable.java b/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/Cacheable.java new file mode 100644 index 00000000000..bf8b09e4378 --- /dev/null +++ b/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/Cacheable.java @@ -0,0 +1,23 @@ +/** + * Copyright (c) 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.repo.common; + + +public interface Cacheable { + + public void clearCache(); +} diff --git a/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/expression/ExpressionFactory.java b/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/expression/ExpressionFactory.java index 61415081825..26d515b2614 100644 --- a/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/expression/ExpressionFactory.java +++ b/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/expression/ExpressionFactory.java @@ -18,12 +18,15 @@ import java.util.HashMap; import java.util.Map; +import javax.annotation.PostConstruct; import javax.xml.namespace.QName; import com.evolveum.midpoint.common.LocalizationService; import com.evolveum.midpoint.prism.ItemDefinition; import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismValue; +import com.evolveum.midpoint.repo.common.CacheRegistry; +import com.evolveum.midpoint.repo.common.Cacheable; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.util.ObjectResolver; import com.evolveum.midpoint.security.api.SecurityContextManager; @@ -38,7 +41,7 @@ * @author semancik * */ -public class ExpressionFactory { +public class ExpressionFactory implements Cacheable { private Map evaluatorFactoriesMap = new HashMap(); private ExpressionEvaluatorFactory defaultEvaluatorFactory; @@ -47,6 +50,7 @@ public class ExpressionFactory { private ObjectResolver objectResolver; // using setter to allow Spring to handle circular references final private SecurityContextManager securityContextManager; private LocalizationService localizationService; + private CacheRegistry cacheRegistry; public ExpressionFactory(SecurityContextManager securityContextManager, PrismContext prismContext, LocalizationService localizationService) { @@ -67,6 +71,19 @@ public LocalizationService getLocalizationService() { return localizationService; } + public void setCacheRegistry(CacheRegistry cacheRegistry) { + this.cacheRegistry = cacheRegistry; + } + + public CacheRegistry getCacheRegistry() { + return cacheRegistry; + } + + @PostConstruct + public void register() { + cacheRegistry.registerCacheableService(this); + } + public Expression makeExpression(ExpressionType expressionType, D outputDefinition, String shortDesc, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException { @@ -167,5 +184,10 @@ private ExpressionFactory getOuterType() { return ExpressionFactory.this; } } + + @Override + public void clearCache() { + cache = new HashMap<>(); + } } diff --git a/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/task/AbstractSearchIterativeResultHandler.java b/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/task/AbstractSearchIterativeResultHandler.java index 7ee5b369bb8..bdeae821354 100644 --- a/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/task/AbstractSearchIterativeResultHandler.java +++ b/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/task/AbstractSearchIterativeResultHandler.java @@ -397,7 +397,7 @@ private void processRequest(ProcessingRequest request, Task workerTask, Operatio } } - // may be overriden + // may be overridden protected String getDisplayName(PrismObject object) { return StatisticsUtil.getDisplayName(object); } diff --git a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java index 1f631ab501f..33ae1784aff 100644 --- a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java +++ b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java @@ -966,6 +966,7 @@ protected void assertCacheMisses(CachingStatistics lastStats, CachingStatistics protected void assertSteadyResources() { assertCounterIncrement(InternalCounters.RESOURCE_REPOSITORY_READ_COUNT, 0); + assertCounterIncrement(InternalCounters.RESOURCE_REPOSITORY_MODIFY_COUNT, 0); assertCounterIncrement(InternalCounters.RESOURCE_SCHEMA_FETCH_COUNT, 0); assertCounterIncrement(InternalCounters.RESOURCE_SCHEMA_PARSE_COUNT, 0); assertCounterIncrement(InternalCounters.CONNECTOR_CAPABILITIES_FETCH_COUNT, 0); @@ -975,6 +976,7 @@ protected void assertSteadyResources() { protected void rememberSteadyResources() { rememberCounter(InternalCounters.RESOURCE_REPOSITORY_READ_COUNT); + rememberCounter(InternalCounters.RESOURCE_REPOSITORY_MODIFY_COUNT); rememberCounter(InternalCounters.RESOURCE_SCHEMA_FETCH_COUNT); rememberCounter(InternalCounters.RESOURCE_SCHEMA_PARSE_COUNT); rememberCounter(InternalCounters.CONNECTOR_CAPABILITIES_FETCH_COUNT); diff --git a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/Checker.java b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/Checker.java index 79bfd19590d..811a86214dd 100644 --- a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/Checker.java +++ b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/Checker.java @@ -27,8 +27,9 @@ public interface Checker { * true = done * false = continue waiting */ - public boolean check() throws CommonException; + boolean check() throws CommonException; - public void timeout(); + default void timeout() { + } } diff --git a/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/TestQuartzTaskManagerContract.java b/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/TestQuartzTaskManagerContract.java index 5f85176d939..814cf172cee 100644 --- a/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/TestQuartzTaskManagerContract.java +++ b/repo/task-quartz-impl/src/test/java/com/evolveum/midpoint/task/quartzimpl/TestQuartzTaskManagerContract.java @@ -564,16 +564,10 @@ public void test005Single() throws Exception { // to pick up this // task - waitFor("Waiting for task manager to execute the task", new Checker() { - public boolean check() throws ObjectNotFoundException, SchemaException { - Task task = taskManager.getTask(taskOid(test), result); - IntegrationTestTools.display("Task while waiting for task manager to execute the task", task); - return task.getExecutionStatus() == TaskExecutionStatus.CLOSED; - } - - @Override - public void timeout() { - } + waitFor("Waiting for task manager to execute the task", () -> { + Task checkedTask = taskManager.getTask(taskOid(test), result); + IntegrationTestTools.display("Task while waiting for task manager to execute the task", checkedTask); + return checkedTask.getExecutionStatus() == TaskExecutionStatus.CLOSED; }, 10000, 1000); logger.info("... done"); diff --git a/testing/rest/src/test/java/com/evolveum/midpoint/testing/rest/TestAbstractRestService.java b/testing/rest/src/test/java/com/evolveum/midpoint/testing/rest/TestAbstractRestService.java index 0c155d13955..b5bedd3d693 100644 --- a/testing/rest/src/test/java/com/evolveum/midpoint/testing/rest/TestAbstractRestService.java +++ b/testing/rest/src/test/java/com/evolveum/midpoint/testing/rest/TestAbstractRestService.java @@ -48,6 +48,7 @@ import com.evolveum.midpoint.util.MiscUtil; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.xml.ns._public.common.api_types_3.ExecuteCredentialResetRequestType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ActivationStatusType; import com.evolveum.midpoint.xml.ns._public.common.common_3.CredentialsType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectTemplateType; @@ -62,6 +63,7 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.SystemObjectsType; import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; import com.evolveum.prism.xml.ns._public.query_3.QueryType; +import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType; public abstract class TestAbstractRestService extends RestServiceInitializer{ @@ -116,6 +118,7 @@ public abstract class TestAbstractRestService extends RestServiceInitializer{ private static final String MODIFICATION_ASSIGN_ROLE_MODIFIER = "modification-assign-role-modifier"; private static final String MODIFICATION_REPLACE_ANSWER = "modification-replace-answer"; private static final String MODIFICATION_FORCE_PASSWORD_CHANGE = "modification-force-password-change"; + private static final String EXECUTE_CREDENTIAL_RESET = "execute-credential-reset"; protected abstract File getRepoFile(String fileBaseName); @@ -1278,6 +1281,55 @@ public void test601modifyPasswordForceChange() throws Exception { assertTrue(BooleanUtils.isTrue(passwordType.isForceChange())); } + + @Test + public void test602resetPassword() throws Exception { + final String TEST_NAME = "test602resetPassword"; + displayTestTitle(this, TEST_NAME); + + WebClient client = prepareClient(); + client.path("/users/" + USER_DARTHADDER_OID + "/credential"); + + getDummyAuditService().clear(); + + TestUtil.displayWhen(TEST_NAME); +// ExecuteCredentialResetRequestType executeCredentialResetRequest = new ExecuteCredentialResetRequestType(); +// executeCredentialResetRequest.setResetMethod("passwordReset"); +// executeCredentialResetRequest.setUserEntry("123passwd456"); + Response response = client.post(getRequestFile(EXECUTE_CREDENTIAL_RESET)); + + TestUtil.displayThen(TEST_NAME); + displayResponse(response); + traceResponse(response); + + assertEquals("Expected 200 but got " + response.getStatus(), 200, response.getStatus()); + + + IntegrationTestTools.display("Audit", getDummyAuditService()); + getDummyAuditService().assertRecords(4); + getDummyAuditService().assertLoginLogout(SchemaConstants.CHANNEL_REST_URI); + getDummyAuditService().assertHasDelta(1, ChangeType.MODIFY, UserType.class); + + TestUtil.displayWhen(TEST_NAME); + client = prepareClient(); + response = client.path("/users/" + USER_DARTHADDER_OID).get(); + + TestUtil.displayThen(TEST_NAME); + displayResponse(response); + + assertEquals("Expected 200 but got " + response.getStatus(), 200, response.getStatus()); + UserType userDarthadder = response.readEntity(UserType.class); + CredentialsType credentials = userDarthadder.getCredentials(); + assertNotNull("No credentials in user. Something is wrong.", credentials); + PasswordType passwordType = credentials.getPassword(); + assertNotNull("No password defined for user. Something is wrong.", passwordType); + ProtectedStringType passwordValue = passwordType.getValue(); + assertNotNull("No value for password defined for user. Something is wrong.", passwordValue); + String passwordClearValue = getPrismContext().getDefaultProtector().decryptString(passwordValue); + assertEquals("Password doesn't match. Expected P4ssw0rd, but was " + passwordClearValue, "P4ssw0rd", passwordClearValue); + assertTrue(BooleanUtils.isTrue(passwordType.isForceChange())); + + } private WebClient prepareClient() { return prepareClient(USER_ADMINISTRATOR_USERNAME, USER_ADMINISTRATOR_PASSWORD); diff --git a/testing/rest/src/test/resources/repo/security-policy.xml b/testing/rest/src/test/resources/repo/security-policy.xml index 116a6cd7332..42c6b46ca9e 100644 --- a/testing/rest/src/test/resources/repo/security-policy.xml +++ b/testing/rest/src/test/resources/repo/security-policy.xml @@ -58,4 +58,11 @@ + + passwordReset + true + + + + diff --git a/testing/rest/src/test/resources/req/json/execute-credential-reset.json b/testing/rest/src/test/resources/req/json/execute-credential-reset.json new file mode 100644 index 00000000000..4a46fcf55ae --- /dev/null +++ b/testing/rest/src/test/resources/req/json/execute-credential-reset.json @@ -0,0 +1,7 @@ +{ + "@ns": "http://midpoint.evolveum.com/xml/ns/public/common/api-types-3", + "executeCredentialResetRequest" : { + "resetMethod" : "passwordReset", + "userEntry" : "P4ssw0rd" + } +} \ No newline at end of file diff --git a/testing/rest/src/test/resources/req/xml/execute-credential-reset.xml b/testing/rest/src/test/resources/req/xml/execute-credential-reset.xml new file mode 100644 index 00000000000..2a7bfdef4ba --- /dev/null +++ b/testing/rest/src/test/resources/req/xml/execute-credential-reset.xml @@ -0,0 +1,24 @@ + + + + + passwordReset + P4ssw0rd + diff --git a/testing/rest/src/test/resources/req/yaml/execute-credential-reset.yml b/testing/rest/src/test/resources/req/yaml/execute-credential-reset.yml new file mode 100644 index 00000000000..369cce41c66 --- /dev/null +++ b/testing/rest/src/test/resources/req/yaml/execute-credential-reset.yml @@ -0,0 +1,20 @@ +# +# ~ Copyright (c) 2010-2013 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. +# +--- +'@ns': "http://midpoint.evolveum.com/xml/ns/public/common/api-types-3" +executeCredentialResetRequest: + resetMethod: "passwordReset" + userEntry: "P4ssw0rd" diff --git a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestMapleLeaf.java b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestMapleLeaf.java index 7dff61b6683..8fa328f2695 100644 --- a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestMapleLeaf.java +++ b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestMapleLeaf.java @@ -41,7 +41,11 @@ import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.util.ShadowUtil; import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.test.IntegrationTestTools; import com.evolveum.midpoint.test.util.MidPointTestConstants; +import com.evolveum.midpoint.test.util.TestUtil; +import com.evolveum.midpoint.util.exception.PolicyViolationException; +import com.evolveum.midpoint.xml.ns._public.common.api_types_3.ExecuteCredentialResetRequestType; import com.evolveum.midpoint.xml.ns._public.common.common_3.CredentialsType; import com.evolveum.midpoint.xml.ns._public.common.common_3.PasswordType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType; @@ -57,6 +61,10 @@ public class TestMapleLeaf extends AbstractStoryTest { public static final File TEST_DIR = new File(MidPointTestConstants.TEST_RESOURCES_DIR, "mapleLeaf"); + private static final File SYSTEM_CONFIGURATION_FILE = new File(TEST_DIR, "system-configuration.xml"); + + private static final File SECURITY_POLICY_FILE = new File(TEST_DIR, "security-policy.xml"); + private static final File RESOURCE_OPENDJ_FILE = new File(TEST_DIR, "resource-opendj.xml"); private static final String RESOURCE_OPENDJ_OID = "10000000-0000-0000-0000-000000000000"; @@ -80,6 +88,11 @@ public static void stopResources() throws Exception { openDJController.stop(); } + @Override + protected File getSystemConfigurationFile() { + return SYSTEM_CONFIGURATION_FILE; + } + @Override public void initSystem(Task initTask, OperationResult initResult) throws Exception { super.initSystem(initTask, initResult); @@ -91,6 +104,7 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti importObjectFromFile(ROLE_META_MONKEY_DONKEY); importObjectFromFile(ROLE_SQUIRREL_FILE); + importObjectFromFile(SECURITY_POLICY_FILE); } @@ -256,4 +270,39 @@ public void test100changePasswordForceChange() throws Exception { openDJController.assertPassword("uid=jack,ou=People,dc=example,dc=com", "oldValue"); } + + @Test + public void test101resetPassword() throws Exception { + final String TEST_NAME = "test101resetPassword"; + displayTestTitle(TEST_NAME); + + Task task = taskManager.createTaskInstance(TEST_NAME); + OperationResult result = task.getResult(); + + openDJController.assertPassword("uid=jack,ou=People,dc=example,dc=com", "oldValue"); + + //when + displayWhen(TEST_NAME); + PrismObject user = getUser(USER_JACK_OID); + ExecuteCredentialResetRequestType executeCredentialResetRequest = new ExecuteCredentialResetRequestType(); + executeCredentialResetRequest.setResetMethod("passwordReset"); + executeCredentialResetRequest.setUserEntry("123passwd456"); + modelInteractionService.executeCredentialsReset(user, executeCredentialResetRequest, task, result); + + //THEN + displayThen(TEST_NAME); + PrismObject userAfter = getUser(USER_JACK_OID); + UserType userTypeAfter = userAfter.asObjectable(); + + CredentialsType credentials = userTypeAfter.getCredentials(); + assertNotNull("Oooops, something unexpected happenned - no credentials found in user " + userAfter, credentials); + PasswordType password = credentials.getPassword(); + assertNotNull("Oooops, something unexpected happenned - no password defined for user " + userAfter, password); + + String clearTextValue = protector.decryptString(password.getValue()); + assertEquals(clearTextValue, "123passwd456", "Passwords don't match"); + assertTrue(BooleanUtils.isTrue(password.isForceChange()), "Expected force change set to true, but was: " + BooleanUtils.isTrue(password.isForceChange())); + + openDJController.assertPassword("uid=jack,ou=People,dc=example,dc=com", "oldValue"); + } } diff --git a/testing/story/src/test/resources/mapleLeaf/security-policy.xml b/testing/story/src/test/resources/mapleLeaf/security-policy.xml new file mode 100644 index 00000000000..fac257f8eaa --- /dev/null +++ b/testing/story/src/test/resources/mapleLeaf/security-policy.xml @@ -0,0 +1,28 @@ + + + + + Default Security Policy + + passwordReset + true + + + + + diff --git a/testing/story/src/test/resources/mapleLeaf/system-configuration.xml b/testing/story/src/test/resources/mapleLeaf/system-configuration.xml new file mode 100644 index 00000000000..d3825e1ff47 --- /dev/null +++ b/testing/story/src/test/resources/mapleLeaf/system-configuration.xml @@ -0,0 +1,67 @@ + + + + + SystemConfiguration + + File Appender + INFO + + TRACE + com.evolveum.midpoint.common.LoggingConfigurationManager + + + TRACE + com.evolveum.midpoint.notifications + + + %date [%thread] %-5level \(%logger{46}\): %message%n + target/test.log + true + + + + + + workItemLifecycleEvent + dummy:workItemLifecycle + + + workItemAllocationEvent + dummy:workItemAllocation + + + workItemCustomEvent + dummy:workItemCustom + + + workflowProcessEvent + dummy:process + + + + target/mail-notifications.log + + + + never + never + + +