mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +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 - 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