mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
[ACS-1455] Schema validation report expansion with patch specific problems told apart (#386)
* Update schema validation report - Introduced changes to tell apart problems due to optional unapplied patches within schema validation report * Update SchemaDifferenceHelper - Now populating optionalUpgradePatches list during the schema bootstrap registration to conform with patch registration mechanising already in use - Added tests * Make minor corrections Co-authored-by: Nana Insaidoo <nana.insaidoo@meterian.com>
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2021 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -40,7 +40,8 @@ public class SchemaUpgradeScriptPatch extends AbstractPatch
|
||||
{
|
||||
private static final String MSG_NOT_EXECUTED = "patch.schemaUpgradeScript.err.not_executed";
|
||||
|
||||
private String scriptUrl;
|
||||
private String scriptUrl;
|
||||
private String problemsPatternFileUrl;
|
||||
|
||||
public SchemaUpgradeScriptPatch()
|
||||
{
|
||||
@@ -52,8 +53,13 @@ public class SchemaUpgradeScriptPatch extends AbstractPatch
|
||||
public String getScriptUrl()
|
||||
{
|
||||
return scriptUrl;
|
||||
}
|
||||
}
|
||||
|
||||
public String getProblemPatternsFileUrl()
|
||||
{
|
||||
return problemsPatternFileUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the URL of the upgrade scriptUrl to execute. This is the full URL of the
|
||||
* file, e.g. <b>classpath:alfresco/patch/scripts/upgrade-1.4/${hibernate.dialect.class}/patchAlfrescoSchemaUpdate-1.4-2.sql</b>
|
||||
@@ -65,12 +71,25 @@ public class SchemaUpgradeScriptPatch extends AbstractPatch
|
||||
public void setScriptUrl(String script)
|
||||
{
|
||||
this.scriptUrl = script;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the URL of the problems pattern file to accompany the upgrade script. This is the full URL of the
|
||||
* file, e.g. <b>classpath:alfresco/patch/scripts/upgrade-1.4/${hibernate.dialect.class}/patchAlfrescoSchemaUpdate-1.4-2-problems.txt</b>
|
||||
* where the <b>${hibernate.dialect.class}</b> placeholder will be substituted with the Hibernate
|
||||
* <code>Dialect</code> as configured for the system.
|
||||
*
|
||||
* @param problemsFile the problems file
|
||||
*/
|
||||
public void setProblemsPatternFileUrl(String problemsFile)
|
||||
{
|
||||
this.problemsPatternFileUrl = problemsFile;
|
||||
}
|
||||
|
||||
protected void checkProperties()
|
||||
{
|
||||
super.checkProperties();
|
||||
checkPropertyNotNull(scriptUrl, "scriptUrl");
|
||||
checkPropertyNotNull(scriptUrl, "scriptUrl");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -79,6 +98,6 @@ public class SchemaUpgradeScriptPatch extends AbstractPatch
|
||||
@Override
|
||||
protected String applyInternal() throws Exception
|
||||
{
|
||||
throw new PatchException(MSG_NOT_EXECUTED, scriptUrl);
|
||||
}
|
||||
throw new PatchException(MSG_NOT_EXECUTED, scriptUrl);
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2021 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -85,12 +85,14 @@ import org.alfresco.util.DialectUtil;
|
||||
import org.alfresco.util.LogUtil;
|
||||
import org.alfresco.util.PropertyCheck;
|
||||
import org.alfresco.util.TempFileProvider;
|
||||
import org.alfresco.util.schemacomp.Difference;
|
||||
import org.alfresco.util.schemacomp.ExportDb;
|
||||
import org.alfresco.util.schemacomp.MultiFileDumper;
|
||||
import org.alfresco.util.schemacomp.MultiFileDumper.DbToXMLFactory;
|
||||
import org.alfresco.util.schemacomp.Result;
|
||||
import org.alfresco.util.schemacomp.Results;
|
||||
import org.alfresco.util.schemacomp.SchemaComparator;
|
||||
import org.alfresco.util.schemacomp.SchemaDifferenceHelper;
|
||||
import org.alfresco.util.schemacomp.XMLToSchema;
|
||||
import org.alfresco.util.schemacomp.model.Schema;
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -124,6 +126,7 @@ public class SchemaBootstrap extends AbstractLifecycleBean
|
||||
private static final String MSG_EXECUTING_COPIED_SCRIPT = "schema.update.msg.executing_copied_script";
|
||||
private static final String MSG_EXECUTING_STATEMENT = "schema.update.msg.executing_statement";
|
||||
private static final String MSG_OPTIONAL_STATEMENT_FAILED = "schema.update.msg.optional_statement_failed";
|
||||
private static final String MSG_OPTIONAL_PATCH_RUN_SUGGESTION = "system.schema_comp.patch_run_suggestion";
|
||||
private static final String ERR_FORCED_STOP = "schema.update.err.forced_stop";
|
||||
private static final String ERR_MULTIPLE_SCHEMAS = "schema.update.err.found_multiple";
|
||||
private static final String ERR_PREVIOUS_FAILED_BOOTSTRAP = "schema.update.err.previous_failed";
|
||||
@@ -153,7 +156,8 @@ public class SchemaBootstrap extends AbstractLifecycleBean
|
||||
|
||||
private static volatile int maxStringLength = DEFAULT_MAX_STRING_LENGTH;
|
||||
private Dialect dialect;
|
||||
|
||||
private SchemaDifferenceHelper differenceHelper;
|
||||
|
||||
private ResourcePatternResolver rpr = new PathMatchingResourcePatternResolver(this.getClass().getClassLoader());
|
||||
|
||||
/**
|
||||
@@ -233,6 +237,11 @@ public class SchemaBootstrap extends AbstractLifecycleBean
|
||||
this.dialect = dialect;
|
||||
}
|
||||
|
||||
public void setDifferenceHelper(SchemaDifferenceHelper differenceHelper)
|
||||
{
|
||||
this.differenceHelper = differenceHelper;
|
||||
}
|
||||
|
||||
private static Log logger = LogFactory.getLog(SchemaBootstrap.class);
|
||||
|
||||
private DescriptorService descriptorService;
|
||||
@@ -1815,7 +1824,7 @@ public class SchemaBootstrap extends AbstractLifecycleBean
|
||||
// Return number of problems found across all reference files.
|
||||
return totalProblems;
|
||||
}
|
||||
|
||||
|
||||
private int validateSchema(Resource referenceResource, String outputFileNameTemplate, PrintWriter out)
|
||||
{
|
||||
try
|
||||
@@ -1916,11 +1925,42 @@ public class SchemaBootstrap extends AbstractLifecycleBean
|
||||
pw = out;
|
||||
}
|
||||
|
||||
Map<String, List<String>> optionalPatchMessages = new HashMap<>();
|
||||
// Populate the file with details of the comparison's results.
|
||||
for (Result result : results)
|
||||
{
|
||||
pw.print(result.describe());
|
||||
String optionalPatchId = findPatchCausingDifference(result, target);
|
||||
String differenceMessage = result.describe();
|
||||
if (optionalPatchId == null)
|
||||
{
|
||||
pw.print(differenceMessage);
|
||||
pw.print(SchemaComparator.LINE_SEPARATOR);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (optionalPatchMessages.containsKey(optionalPatchId))
|
||||
{
|
||||
optionalPatchMessages.get(optionalPatchId).add(differenceMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
List<String> newResults = new ArrayList<>();
|
||||
newResults.add(differenceMessage);
|
||||
optionalPatchMessages.put(optionalPatchId, newResults);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (String optionalPatchId: optionalPatchMessages.keySet())
|
||||
{
|
||||
pw.print(SchemaComparator.LINE_SEPARATOR);
|
||||
pw.print(I18NUtil.getMessage(MSG_OPTIONAL_PATCH_RUN_SUGGESTION, optionalPatchId));
|
||||
pw.print(SchemaComparator.LINE_SEPARATOR);
|
||||
for (String optionalPatchMessage: optionalPatchMessages.get(optionalPatchId))
|
||||
{
|
||||
pw.print(optionalPatchMessage);
|
||||
pw.print(SchemaComparator.LINE_SEPARATOR);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
@@ -1946,7 +1986,7 @@ public class SchemaBootstrap extends AbstractLifecycleBean
|
||||
}
|
||||
else
|
||||
{
|
||||
LogUtil.warn(logger, WARN_SCHEMA_COMP_PROBLEMS_FOUND, numProblems, outputFile);
|
||||
LogUtil.warn(logger, WARN_SCHEMA_COMP_PROBLEMS_FOUND, numProblems, outputFile);
|
||||
}
|
||||
}
|
||||
Date endTime = new Date();
|
||||
@@ -1956,6 +1996,17 @@ public class SchemaBootstrap extends AbstractLifecycleBean
|
||||
return results.size();
|
||||
}
|
||||
|
||||
private String findPatchCausingDifference(Result result, Schema currentDb)
|
||||
{
|
||||
// In new installations of the system the schema validation is run twice. Since none of the alf_ tables is present there is no need to seek for unapplied patches.
|
||||
if (!currentDb.containsByName("alf_applied_patch"))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return differenceHelper.findPatchCausingDifference((Difference)result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces schema dump in XML format: this is performed pre- and post-upgrade (i.e. if
|
||||
* changes are made to the schema) and can made upon demand via JMX.
|
||||
|
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2021 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -29,7 +29,8 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.repo.admin.patch.impl.SchemaUpgradeScriptPatch;
|
||||
import org.alfresco.util.PropertyCheck;
|
||||
import org.alfresco.util.PropertyCheck;
|
||||
import org.alfresco.util.schemacomp.SchemaDifferenceHelper;
|
||||
|
||||
/**
|
||||
* Registers a list of create scripts.
|
||||
@@ -44,7 +45,8 @@ public class SchemaBootstrapRegistration
|
||||
private List<String> postCreateScriptUrls;
|
||||
private List<SchemaUpgradeScriptPatch> preUpdateScriptPatches;
|
||||
private List<SchemaUpgradeScriptPatch> postUpdateScriptPatches;
|
||||
private List<SchemaUpgradeScriptPatch> updateActivitiScriptPatches;
|
||||
private List<SchemaUpgradeScriptPatch> updateActivitiScriptPatches;
|
||||
private SchemaDifferenceHelper differenceHelper;
|
||||
|
||||
public SchemaBootstrapRegistration()
|
||||
{
|
||||
@@ -61,6 +63,14 @@ public class SchemaBootstrapRegistration
|
||||
public void setSchemaBootstrap(SchemaBootstrap schemaBootstrap)
|
||||
{
|
||||
this.schemaBootstrap = schemaBootstrap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param differenceHelper the component with which to register upgrade script pacthes
|
||||
*/
|
||||
public void setDifferenceHelper(SchemaDifferenceHelper differenceHelper)
|
||||
{
|
||||
this.differenceHelper = differenceHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,7 +149,8 @@ public class SchemaBootstrapRegistration
|
||||
}
|
||||
for (SchemaUpgradeScriptPatch postUpdateScriptPatch : postUpdateScriptPatches)
|
||||
{
|
||||
schemaBootstrap.addPostUpdateScriptPatch(postUpdateScriptPatch);
|
||||
schemaBootstrap.addPostUpdateScriptPatch(postUpdateScriptPatch);
|
||||
differenceHelper.addUpgradeScriptPatch(postUpdateScriptPatch);
|
||||
}
|
||||
for (SchemaUpgradeScriptPatch updateActivitiScriptPatch : updateActivitiScriptPatches)
|
||||
{
|
||||
|
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2021 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.util.schemacomp;
|
||||
|
||||
import static java.util.Locale.ENGLISH;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.repo.admin.patch.PatchService;
|
||||
import org.alfresco.repo.admin.patch.impl.SchemaUpgradeScriptPatch;
|
||||
import org.alfresco.repo.domain.dialect.Dialect;
|
||||
import org.alfresco.util.DialectUtil;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.extensions.surf.util.I18NUtil;
|
||||
|
||||
public class SchemaDifferenceHelper
|
||||
{
|
||||
private static Log logger = LogFactory.getLog(SchemaDifferenceHelper.class);
|
||||
|
||||
private Dialect dialect;
|
||||
private PatchService patchService;
|
||||
private List<SchemaUpgradeScriptPatch> optionalUpgradePatches;
|
||||
private ResourcePatternResolver rpr = new PathMatchingResourcePatternResolver(this.getClass().getClassLoader());
|
||||
|
||||
public SchemaDifferenceHelper(Dialect dialect, PatchService patchService)
|
||||
{
|
||||
this.dialect = dialect;
|
||||
this.patchService = patchService;
|
||||
this.optionalUpgradePatches = new ArrayList<SchemaUpgradeScriptPatch>(4);
|
||||
}
|
||||
|
||||
public SchemaDifferenceHelper(Dialect dialect, PatchService patchService,
|
||||
List<SchemaUpgradeScriptPatch> upgradePatches)
|
||||
{
|
||||
this.dialect = dialect;
|
||||
this.patchService = patchService;
|
||||
this.optionalUpgradePatches = upgradePatches;
|
||||
}
|
||||
|
||||
public void addUpgradeScriptPatch(SchemaUpgradeScriptPatch patch)
|
||||
{
|
||||
if (patch.isIgnored())
|
||||
{
|
||||
this.optionalUpgradePatches.add(patch);
|
||||
}
|
||||
}
|
||||
|
||||
public String findPatchCausingDifference(Difference difference)
|
||||
{
|
||||
for (SchemaUpgradeScriptPatch patch: optionalUpgradePatches)
|
||||
{
|
||||
if (!isPatchApplied(patch))
|
||||
{
|
||||
List<String> problemPatterns = getProblemsPatterns(patch);
|
||||
for (String problemPattern: problemPatterns)
|
||||
{
|
||||
if (describe(difference).matches(problemPattern))
|
||||
{
|
||||
return patch.getId();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isPatchApplied(SchemaUpgradeScriptPatch patch)
|
||||
{
|
||||
return patchService.getPatch(patch.getId()) != null;
|
||||
}
|
||||
|
||||
protected Resource getDialectResource(String resourceUrl)
|
||||
{
|
||||
if(resourceUrl == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return DialectUtil.getDialectResource(rpr, dialect.getClass(), resourceUrl);
|
||||
}
|
||||
|
||||
private List<String> getProblemsPatterns(SchemaUpgradeScriptPatch patch)
|
||||
{
|
||||
List<String> optionalProblems = new ArrayList<>();
|
||||
String problemFileUrl = patch.getProblemPatternsFileUrl();
|
||||
Resource problemFile = getDialectResource(problemFileUrl);
|
||||
|
||||
if (problemFile != null)
|
||||
{
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(problemFile.getInputStream(), StandardCharsets.UTF_8)))
|
||||
{
|
||||
String line = reader.readLine();
|
||||
while (line != null)
|
||||
{
|
||||
optionalProblems.add(line);
|
||||
line = reader.readLine();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.error("Error while parsing problems patterns for patch " + patch.getId() + ex);
|
||||
}
|
||||
}
|
||||
|
||||
return optionalProblems;
|
||||
}
|
||||
|
||||
protected String describe(Difference difference)
|
||||
{
|
||||
if (difference.getLeft() == null)
|
||||
{
|
||||
return I18NUtil.getMessage(
|
||||
"system.schema_comp.diff.target_only",
|
||||
ENGLISH,
|
||||
difference.getRight().getDbObject().getTypeName(),
|
||||
difference.getRight().getPath(),
|
||||
difference.getRight().getPropertyValue());
|
||||
}
|
||||
if (difference.getRight() == null)
|
||||
{
|
||||
return I18NUtil.getMessage(
|
||||
"system.schema_comp.diff.ref_only",
|
||||
ENGLISH,
|
||||
difference.getLeft().getDbObject().getTypeName(),
|
||||
difference.getLeft().getPath(),
|
||||
difference.getLeft().getPropertyValue());
|
||||
}
|
||||
|
||||
return I18NUtil.getMessage(
|
||||
"system.schema_comp.diff",
|
||||
ENGLISH,
|
||||
difference.getLeft().getDbObject().getTypeName(),
|
||||
difference.getLeft().getPath(),
|
||||
difference.getLeft().getPropertyValue(),
|
||||
difference.getRight().getPath(),
|
||||
difference.getRight().getPropertyValue());
|
||||
}
|
||||
}
|
@@ -96,6 +96,14 @@
|
||||
<value>classpath:alfresco/dbscripts/create/${db.script.dialect}/Schema-Reference-ACT.xml</value>
|
||||
</list>
|
||||
</property>
|
||||
<property name="differenceHelper">
|
||||
<ref bean="differenceHelper" />
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="differenceHelper" class="org.alfresco.util.schemacomp.SchemaDifferenceHelper">
|
||||
<constructor-arg ref="dialect"/>
|
||||
<constructor-arg ref="patchComponent"/>
|
||||
</bean>
|
||||
|
||||
<bean id="encryptionChecker" class="org.alfresco.encryption.EncryptionChecker">
|
||||
|
@@ -29,6 +29,7 @@
|
||||
|
||||
<bean id="schema.upgrade.core" class="org.alfresco.repo.domain.schema.SchemaBootstrapRegistration" init-method="register">
|
||||
<property name="schemaBootstrap" ref="schemaBootstrap" />
|
||||
<property name="differenceHelper" ref="differenceHelper" />
|
||||
<property name="preUpdateScriptPatches">
|
||||
<list>
|
||||
<ref bean="patch.db-V4.1-update-activiti-nullable-columns" />
|
||||
|
@@ -37,6 +37,8 @@ system.schema_comp.name_validator=name must match pattern ''{0}''
|
||||
system.schema_comp.index_columns_validator=Number of columns in index doesn''t match. Was {0}, but expected {1}
|
||||
system.schema_comp.column_names_validator=Column types do not match. Was {0}, but expected {1}
|
||||
system.schema_comp.schema_version_validator=version must be at least ''{0}''
|
||||
# Optional long running patch messages...
|
||||
system.schema_comp.patch_run_suggestion=The following problems will be resolved once the long running patch {0} has been run
|
||||
|
||||
# Clustering
|
||||
system.cluster.license.not_enabled=License does not permit clustering: clustering is disabled.
|
||||
|
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2021 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -233,7 +233,9 @@ import org.junit.runners.Suite;
|
||||
org.alfresco.repo.rendition2.TransformationOptionsConverterTest.class,
|
||||
org.alfresco.transform.client.registry.TransformServiceRegistryConfigTest.class,
|
||||
|
||||
org.alfresco.repo.event2.RepoEvent2UnitSuite.class
|
||||
org.alfresco.repo.event2.RepoEvent2UnitSuite.class,
|
||||
|
||||
org.alfresco.util.schemacomp.SchemaDifferenceHelperUnitTest.class
|
||||
})
|
||||
public class AllUnitTestsSuite
|
||||
{
|
||||
|
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2017 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2021 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -85,6 +85,7 @@ import org.junit.runners.Suite;
|
||||
org.alfresco.util.schemacomp.DbToXMLTest.class,
|
||||
org.alfresco.util.schemacomp.ExportDbTest.class,
|
||||
org.alfresco.util.schemacomp.SchemaReferenceFileTest.class,
|
||||
org.alfresco.util.schemacomp.SchemaBootstrapTest.class,
|
||||
org.alfresco.repo.module.ModuleComponentHelperTest.class,
|
||||
org.alfresco.repo.node.getchildren.GetChildrenCannedQueryTest.class,
|
||||
|
||||
|
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2021 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.util.schemacomp;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.repo.admin.patch.impl.SchemaUpgradeScriptPatch;
|
||||
import org.alfresco.repo.domain.schema.SchemaBootstrap;
|
||||
import org.alfresco.test_category.OwnJVMTestsCategory;
|
||||
import org.alfresco.util.test.junitrules.ApplicationContextInit;
|
||||
import org.junit.Before;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.experimental.categories.Category;
|
||||
import org.junit.rules.RuleChain;
|
||||
|
||||
@Category({OwnJVMTestsCategory.class})
|
||||
public class SchemaBootstrapTest
|
||||
{
|
||||
private static final String BOOTSTRAP_TEST_CONTEXT = "classpath*:alfresco/dbscripts/test-bootstrap-context.xml";
|
||||
private static final List<String> TEST_SCHEMA_REFERENCE_URLS = Arrays.asList(
|
||||
"classpath:alfresco/dbscripts/create/${db.script.dialect}/Test-Schema-Reference-ALF.xml",
|
||||
"classpath:alfresco/dbscripts/create/${db.script.dialect}/Schema-Reference-ACT.xml");
|
||||
|
||||
private static ApplicationContextInit APP_CONTEXT_INIT = ApplicationContextInit.createStandardContextWithOverrides(BOOTSTRAP_TEST_CONTEXT);
|
||||
|
||||
@ClassRule
|
||||
public static RuleChain staticRuleChain = RuleChain.outerRule(APP_CONTEXT_INIT);
|
||||
|
||||
private SchemaBootstrap schemaBootstrap;
|
||||
private SchemaUpgradeScriptPatch optionalPatch;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
schemaBootstrap = (SchemaBootstrap) APP_CONTEXT_INIT.getApplicationContext().getBean("schemaBootstrap");
|
||||
schemaBootstrap.setSchemaReferenceUrls(TEST_SCHEMA_REFERENCE_URLS);
|
||||
optionalPatch = (SchemaUpgradeScriptPatch) APP_CONTEXT_INIT.getApplicationContext().getBean("patchDbVOAddIndexTest");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldSchemaValidationReportProblemsCausedByUnappliedOptionalPatch()
|
||||
{
|
||||
ByteArrayOutputStream buff = new ByteArrayOutputStream();
|
||||
|
||||
PrintWriter out = new PrintWriter(buff);
|
||||
int numProblems = schemaBootstrap.validateSchema(null, out);
|
||||
out.flush();
|
||||
|
||||
assertEquals(1, numProblems);
|
||||
String problems = buff.toString();
|
||||
assertTrue("Missing optional patch-specific problems report: \n" + problems,
|
||||
problems.contains("The following problems will be resolved once the long running patch "
|
||||
+ optionalPatch.getId() + " has been run"));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2021 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.util.schemacomp;
|
||||
|
||||
import static org.alfresco.util.schemacomp.Difference.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.repo.admin.patch.AppliedPatch;
|
||||
import org.alfresco.repo.admin.patch.PatchService;
|
||||
import org.alfresco.repo.admin.patch.impl.SchemaUpgradeScriptPatch;
|
||||
import org.alfresco.repo.domain.dialect.Dialect;
|
||||
import org.alfresco.util.schemacomp.model.Index;
|
||||
import org.alfresco.util.schemacomp.model.Schema;
|
||||
import org.alfresco.util.schemacomp.model.Table;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.springframework.core.io.InputStreamResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
public class SchemaDifferenceHelperUnitTest
|
||||
{
|
||||
private static final String TEST_PATCH_ID = "patch.db-V1.0-test";
|
||||
private static final String BASE_PROBLEM_PATTERN = ".*missing %s.*%s";
|
||||
|
||||
private SchemaDifferenceHelper differenceHelper;
|
||||
private PatchService patchService;
|
||||
private Dialect dialect;
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder testFolder = new TemporaryFolder();
|
||||
|
||||
@Before
|
||||
public void setup()
|
||||
{
|
||||
dialect = mock(Dialect.class);
|
||||
patchService = mock(PatchService.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotFindPatchWhenThereAreNoUpgradePatches()
|
||||
{
|
||||
Difference diff = createDifference();
|
||||
differenceHelper = createHelper(Arrays.asList());
|
||||
|
||||
assertNull(differenceHelper.findPatchCausingDifference(diff));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotFindPatchWhenUpgradePatchHasBeenApplied() throws IOException
|
||||
{
|
||||
Difference diff = createDifference();
|
||||
SchemaUpgradeScriptPatch upgradeScript = createUpgradeScript(TEST_PATCH_ID);
|
||||
when(patchService.getPatch(TEST_PATCH_ID)).thenReturn(new AppliedPatch());
|
||||
|
||||
differenceHelper = createHelper(Arrays.asList(upgradeScript));
|
||||
String result = differenceHelper.findPatchCausingDifference(diff);
|
||||
|
||||
assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotFindPatchWhenUpgradePatchDoesNotProvideAnyProblemPatternsFile() throws IOException
|
||||
{
|
||||
Difference diff = createDifference();
|
||||
SchemaUpgradeScriptPatch upgradeScript = createUpgradeScript(TEST_PATCH_ID);
|
||||
upgradeScript.setProblemsPatternFileUrl(null);
|
||||
when(patchService.getPatch(TEST_PATCH_ID)).thenReturn(null);
|
||||
|
||||
differenceHelper = createHelper(Arrays.asList(upgradeScript));
|
||||
String result = differenceHelper.findPatchCausingDifference(diff);
|
||||
|
||||
assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFindPatchWhenDifferenceCausedByUpgradePatchIsDetected() throws IOException
|
||||
{
|
||||
Index index = createTableIndex("alf_node");
|
||||
Difference diff = new Difference(Where.ONLY_IN_REFERENCE, new DbProperty(index), null);
|
||||
SchemaUpgradeScriptPatch upgradeScript = createUpgradeScript(TEST_PATCH_ID,
|
||||
String.format(BASE_PROBLEM_PATTERN, index.getTypeName(), "idx_alf_node_test"));
|
||||
when(patchService.getPatch(TEST_PATCH_ID)).thenReturn(null);
|
||||
|
||||
differenceHelper = createHelper(Arrays.asList(upgradeScript));
|
||||
String result = differenceHelper.findPatchCausingDifference(diff);
|
||||
|
||||
assertEquals(TEST_PATCH_ID, result);
|
||||
}
|
||||
|
||||
private Difference createDifference()
|
||||
{
|
||||
Difference difference = new Difference(Where.IN_BOTH_BUT_DIFFERENCE, mock(DbProperty.class), mock(DbProperty.class));
|
||||
return difference;
|
||||
}
|
||||
|
||||
private Index createTableIndex(String tableName)
|
||||
{
|
||||
Table table = new Table(tableName);
|
||||
table.setParent(new Schema(""));
|
||||
return new Index(table, "idx_alf_node_test", Arrays.asList("col_a", "col_b"));
|
||||
}
|
||||
|
||||
private SchemaUpgradeScriptPatch createUpgradeScript(String id, String problemPattern) throws IOException
|
||||
{
|
||||
SchemaUpgradeScriptPatch upgradeScript = new SchemaUpgradeScriptPatch();
|
||||
upgradeScript.setId(id);
|
||||
Path file = createTempFile(problemPattern);
|
||||
upgradeScript.setProblemsPatternFileUrl(file.toAbsolutePath().toString());
|
||||
return upgradeScript;
|
||||
}
|
||||
|
||||
private SchemaUpgradeScriptPatch createUpgradeScript(String id) throws IOException
|
||||
{
|
||||
return createUpgradeScript(id, "");
|
||||
}
|
||||
|
||||
private Path createTempFile() throws IOException
|
||||
{
|
||||
return Files.createTempFile(testFolder.getRoot().toPath(), null, "txt");
|
||||
}
|
||||
|
||||
private Path createTempFile(String content) throws IOException
|
||||
{
|
||||
Path tempFile = createTempFile();
|
||||
Files.write(tempFile, content.getBytes(StandardCharsets.UTF_8));
|
||||
return tempFile;
|
||||
}
|
||||
|
||||
private SchemaDifferenceHelper createHelper(List<SchemaUpgradeScriptPatch> upgradePatches)
|
||||
{
|
||||
return new SchemaDifferenceHelper(dialect, patchService, upgradePatches) {
|
||||
@Override
|
||||
protected String describe(Difference difference)
|
||||
{
|
||||
if (difference.getLeft() == null)
|
||||
{
|
||||
return String.format("Difference: unexpected %s found in database with path: %s",
|
||||
|
||||
difference.getRight().getDbObject().getTypeName(),
|
||||
difference.getRight().getPath());
|
||||
}
|
||||
if(difference.getRight() == null)
|
||||
{
|
||||
return String.format("Difference: missing %s from database, expected at path: %s",
|
||||
difference.getLeft().getDbObject().getTypeName(),
|
||||
difference.getLeft().getPath());
|
||||
}
|
||||
|
||||
return String.format("Difference: expected %s %s=\"%s\", but was %s=\"%s\"",
|
||||
difference.getLeft().getDbObject().getTypeName(),
|
||||
difference.getLeft().getPath(),
|
||||
difference.getLeft().getPropertyValue(),
|
||||
difference.getRight().getPath(),
|
||||
difference.getRight().getPropertyValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Resource getDialectResource(String resourceUrl)
|
||||
{
|
||||
try
|
||||
{
|
||||
return new InputStreamResource(new FileInputStream(resourceUrl));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,60 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/util
|
||||
http://www.springframework.org/schema/util/spring-util-2.5.xsd">
|
||||
|
||||
<bean id="schema.upgrade.core" class="org.alfresco.repo.domain.schema.SchemaBootstrapRegistration" init-method="register">
|
||||
<property name="schemaBootstrap" ref="schemaBootstrap" />
|
||||
<property name="differenceHelper" ref="differenceHelper" />
|
||||
<property name="preUpdateScriptPatches">
|
||||
<list>
|
||||
<ref bean="patch.db-V4.1-update-activiti-nullable-columns" />
|
||||
</list>
|
||||
</property>
|
||||
<property name="postUpdateScriptPatches">
|
||||
<list>
|
||||
<ref bean="patch.db-V4.0-SolrTracking" />
|
||||
<ref bean="patch.db-V4.0-AclChangeSet2" />
|
||||
<ref bean="patch.db-V4.0-TenantTables" />
|
||||
<ref bean="patch.db-V4.1-NodeDeleted" />
|
||||
<ref bean="patch.db-V4.1-drop-alfqname-fk-indexes" />
|
||||
<ref bean="patch.db-V4.2-remove-index-acl_id" />
|
||||
<ref bean="patch.db-V4.1-drop-activiti-feed-format" />
|
||||
<ref bean="patch.db-V4.2-metadata-query-indexes" />
|
||||
<ref bean="patch.db-V4.1-fix-Repo-seqs-order" />
|
||||
<ref bean="patch.db-V4.1-ChildAssoc-OrderBy" />
|
||||
<ref bean="patch.db-V4.1-createIdxAlfNodeTQN" />
|
||||
<ref bean="patch.db-V4.2-restructure-idx_alf_nprop_s-MSSQL" />
|
||||
<ref bean="patch.db-V4.2-migrate-locale-multilingual" />
|
||||
<ref bean="patch.db-V4.1-AuthorizationTables" />
|
||||
<ref bean="patch.db-V5.0-ContentUrlEncryptionTables" />
|
||||
<ref bean="patch.db-V5.1-metadata-query-indexes" />
|
||||
<ref bean="patch.db-V5.2-remove-jbpm-tables-from-db" />
|
||||
<ref bean="patch.db-V6.0-change-set-indexes" />
|
||||
<ref bean="patch.db-V6.3-add-indexes-node-transaction" />
|
||||
<ref bean="patch.db-V0-add-index-test" />
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<alias name="patch.db-V0-add-index-test" alias="patchDbVOAddIndexTest" />
|
||||
<bean id="patch.db-V0-add-index-test" class="org.alfresco.repo.admin.patch.impl.SchemaUpgradeScriptPatch" parent="basePatch">
|
||||
<property name="id"><value>patch.db-V0-add-index-test</value></property>
|
||||
<property name="description"><value>patch.db-V0-add-index-test.description</value></property>
|
||||
<property name="fixesFromSchema"><value>0</value></property>
|
||||
<property name="fixesToSchema"><value>15000</value></property>
|
||||
<property name="targetSchema"><value>15001</value></property>
|
||||
<property name="ignored"><value>${system.new-node-transaction-indexes.ignored}</value></property>
|
||||
<property name="scriptUrl">
|
||||
<value>classpath:alfresco/dbscripts/upgrade/0/${db.script.dialect}/add-index-test.sql</value>
|
||||
</property>
|
||||
<property name="problemsPatternFileUrl">
|
||||
<value>classpath:alfresco/dbscripts/upgrade/0/${db.script.dialect}/add-index-test-problem-patterns.txt</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
</beans>
|
@@ -0,0 +1 @@
|
||||
.*missing index.*.alf_node.idx_alf_node_test
|
@@ -0,0 +1,15 @@
|
||||
|
||||
CREATE INDEX idx_alf_node_test ON alf_node (acl_id, audit_creator); --(optional)
|
||||
|
||||
|
||||
--
|
||||
-- Record script finish
|
||||
--
|
||||
DELETE FROM alf_applied_patch WHERE id = 'patch.db-V0-add-index-test';
|
||||
INSERT INTO alf_applied_patch
|
||||
(id, description, fixes_from_schema, fixes_to_schema, applied_to_schema, target_schema, applied_on_date, applied_to_server, was_executed, succeeded, report)
|
||||
VALUES
|
||||
(
|
||||
'patch.db-V0-add-index-test', 'Manually executed script upgrade V0: Added new index test',
|
||||
0, 15000, -1, 15001, null, 'UNKNOWN', ${TRUE}, ${TRUE}, 'Script completed'
|
||||
);
|
Reference in New Issue
Block a user