/* * Copyright (C) 2003-2016 eXo Platform SAS. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.exoplatform.platform.upgrade.test; import java.util.Collections; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import javax.jcr.Node; import javax.jcr.NodeIterator; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.query.InvalidQueryException; import javax.jcr.query.Query; import org.exoplatform.commons.api.settings.SettingService; import org.exoplatform.commons.testing.BaseExoTestCase; import org.exoplatform.container.PortalContainer; import org.exoplatform.container.component.RequestLifeCycle; import org.exoplatform.container.xml.InitParams; import org.exoplatform.container.xml.ValueParam; import org.exoplatform.container.xml.ValuesParam; import org.exoplatform.platform.upgrade.plugins.MixinCleanerUpgradePlugin; import org.exoplatform.services.jcr.RepositoryService; import org.exoplatform.services.jcr.core.ManageableRepository; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; import org.exoplatform.services.transaction.TransactionService; import org.exoplatform.social.core.activity.model.ExoSocialActivity; import org.exoplatform.social.core.activity.model.ExoSocialActivityImpl; import org.exoplatform.social.core.identity.model.Identity; import org.exoplatform.social.core.identity.provider.OrganizationIdentityProvider; import org.exoplatform.social.core.manager.ActivityManager; import org.exoplatform.social.core.manager.IdentityManager; /** * Created by The eXo Platform SAS Author : Boubaker Khanfir * bkhanfir@exoplatform.com April 16, 2016 */ public class MixinCleanerUpdaterTest extends BaseExoTestCase { private static final String OLD_VERSION = "1.0"; private static final String NEW_VERSION = "1.1"; private static final String WS_NAME = "portal-test"; private final Log LOG = ExoLogger.getLogger(MixinCleanerUpdaterTest.class); private Set<ExoSocialActivity> tearDownActivityList; private Set<Identity> tearDownIdentityList; private IdentityManager identityManager; private ActivityManager activityManager; private RepositoryService repositoryService; private TransactionService transactionService; private SettingService settingService; protected Session session; @Override public void setUp() throws Exception { super.setUp(); identityManager = getContainer().getComponentInstanceOfType(IdentityManager.class); activityManager = getContainer().getComponentInstanceOfType(ActivityManager.class); repositoryService = getContainer().getComponentInstanceOfType(RepositoryService.class); transactionService = getContainer().getComponentInstanceOfType(TransactionService.class); settingService = getContainer().getComponentInstanceOfType(SettingService.class); tearDownActivityList = new HashSet<ExoSocialActivity>(); tearDownIdentityList = new HashSet<Identity>(); for (int i = 0; i < 5; i++) { RequestLifeCycle.begin(PortalContainer.getInstance()); try { createActivity("jame"); createActivity("paul"); createActivity("root"); createActivity("john"); createActivity("mary"); createActivity("demo"); createActivity("ghost"); createActivity("raul"); } finally { RequestLifeCycle.end(); } } session = getSession(); } public void testUpgrade() throws Exception { assertEquals("Used workspace is different", session.getWorkspace().getName(), WS_NAME); // Get the number of nodes that wasn't updated NodeIterator nodeIterator = getQueryResult("select * from soc:profiledefinition", Query.SQL); // exceptional nodes = (soc:profiledefinition COUNT) long exceptionalNodesCount = nodeIterator.getSize(); LOG.info("Nodes of type soc:profiledefinition = {}", nodeIterator.getSize()); // Get nodes count with mixin exo:sortable nodeIterator = getQueryResult("select * from exo:sortable", Query.SQL); assertTrue("No nodes was found with mixin exo:sortable", nodeIterator.getSize() > exceptionalNodesCount); long mixinNodesCount = nodeIterator.getSize() - exceptionalNodesCount; LOG.info("Cleanup '{}' social nodes.", nodeIterator.getSize() - exceptionalNodesCount); String pluginName = "SocialMixinCleanerUpgradePlugin"; // Upgrade 100 first elements MixinCleanerUpgradePlugin socialMixinCleanerUpgradePlugin = new MixinCleanerUpgradePlugin(PortalContainer.getInstance(), repositoryService, transactionService, settingService, setInitParams(100)); socialMixinCleanerUpgradePlugin.setName(pluginName); socialMixinCleanerUpgradePlugin.processUpgrade(OLD_VERSION, NEW_VERSION); assertTrue("Should process to upgrade is 'False'", socialMixinCleanerUpgradePlugin.shouldProceedToUpgrade(NEW_VERSION, OLD_VERSION)); // Wait until the upgrade is asynchronously finished while (!socialMixinCleanerUpgradePlugin.isUpgradeFinished()) { Thread.sleep(1000); } assertEquals("The number of treated nodes is not as expected", socialMixinCleanerUpgradePlugin.getTotalCount(), 100); mixinNodesCount -= 100; String migrationStatus = socialMixinCleanerUpgradePlugin.getValue(MixinCleanerUpgradePlugin.MIGRATION_STATUS); assertNotSame("Migration status is not coherent. ", migrationStatus, MixinCleanerUpgradePlugin.UPGRADE_COMPLETED_STATUS); // Upgrade remaining nodes socialMixinCleanerUpgradePlugin = new MixinCleanerUpgradePlugin(PortalContainer.getInstance(), repositoryService, transactionService, settingService, setInitParams(0)); socialMixinCleanerUpgradePlugin.setName(pluginName); assertTrue("Should process to upgrade is 'False'", socialMixinCleanerUpgradePlugin.shouldProceedToUpgrade(NEW_VERSION, OLD_VERSION)); socialMixinCleanerUpgradePlugin.processUpgrade(OLD_VERSION, NEW_VERSION); // Wait until the upgrade is asynchronously finished while (!socialMixinCleanerUpgradePlugin.isUpgradeFinished()) { Thread.sleep(1000); } migrationStatus = socialMixinCleanerUpgradePlugin.getValue(MixinCleanerUpgradePlugin.MIGRATION_STATUS); assertEquals("Migration status is not coherent. ", migrationStatus, MixinCleanerUpgradePlugin.UPGRADE_COMPLETED_STATUS); // Get nodes of type exo:sortable count again nodeIterator = getQueryResult("select * from exo:sortable", Query.SQL); long nodesCount = nodeIterator.getSize(); // FIXME: workaround JCR-2443 if (nodeIterator.getSize() != exceptionalNodesCount) { while (nodeIterator.hasNext()) { Node node = nodeIterator.nextNode(); if (!node.isNodeType("exo:sortable")) { // LOG.warn("Bug JCR-2443 happened on node '{}', node type '{}'.", // node.getPath(), node.getPrimaryNodeType().getName()); nodesCount--; } } } nodeIterator = getQueryResult("select * from exo:sortable", Query.SQL); // FIXME: workaround JCR-2443 if (nodeIterator.getSize() != exceptionalNodesCount) { while (nodeIterator.hasNext()) { Node node = nodeIterator.nextNode(); if (node.isNodeType("exo:sortable") && !node.isNodeType("soc:profiledefinition")) { LOG.error("Node wasn't cleaned up '{}', node type '{}'.", node.getPath(), node.getPrimaryNodeType().getName()); } } } assertEquals("Social nodes wasn't cleaned up. It seems that there are some remaining nodes that uses exo:sortable", exceptionalNodesCount, nodesCount); assertTrue("Treated nodes are different from what was initially predicted", mixinNodesCount <= socialMixinCleanerUpgradePlugin.getTotalCount()); // Since the upgrade is completed, tests if 'shouldProceedToUpgrade' on upgrade plugin returns false socialMixinCleanerUpgradePlugin = new MixinCleanerUpgradePlugin(PortalContainer.getInstance(), repositoryService, transactionService, settingService, setInitParams(0)); socialMixinCleanerUpgradePlugin.setName(pluginName); assertFalse("The upgrade is completed, but the upgrade plugin is executed again", socialMixinCleanerUpgradePlugin.shouldProceedToUpgrade(NEW_VERSION, OLD_VERSION)); } @Override public void tearDown() throws Exception { for (ExoSocialActivity activity : tearDownActivityList) { activityManager.deleteActivity(activity.getId()); } for (Identity identity : tearDownIdentityList) { identityManager.deleteIdentity(identity); } } @SuppressWarnings("deprecation") private void createActivity(String userId) { Identity identity = identityManager.getOrCreateIdentity(OrganizationIdentityProvider.NAME, userId, true); tearDownIdentityList.add(identity); ExoSocialActivity activity = new ExoSocialActivityImpl(); // test for reserving order of map values for i18n activity Map<String, String> templateParams = new LinkedHashMap<String, String>(); templateParams.put("key1", "value 1"); templateParams.put("key2", "value 2"); templateParams.put("key3", "value 3"); activity.setTemplateParams(templateParams); activity.setTitle("Activity Test for " + userId); activity.setUserId(identity.getId()); // activity.isHidden(false); activity.isLocked(true); activity = activityManager.saveActivity(identity, activity); tearDownActivityList.add(activity); } private NodeIterator getQueryResult(String statement, String type) throws InvalidQueryException, RepositoryException { Query query = session.getWorkspace().getQueryManager().createQuery(statement, type); NodeIterator nodeIterator = query.execute().getNodes(); return nodeIterator; } private InitParams setInitParams(long maxNodesToTreat) { InitParams initParams = new InitParams(); ValueParam workspaceParam = new ValueParam(); workspaceParam.setName("workspace"); workspaceParam.setValue(WS_NAME); ValueParam maxNodesToTreatParam = new ValueParam(); maxNodesToTreatParam.setName("mixinsCleanup.maxNodes"); maxNodesToTreatParam.setValue("" + maxNodesToTreat); ValueParam groupIdParam = new ValueParam(); groupIdParam.setName("product.group.id"); groupIdParam.setValue("org.exoplatform.social"); ValuesParam mixinsParam = new ValuesParam(); mixinsParam.setName("mixinsCleanup.includes"); mixinsParam.setValues(Collections.singletonList("exo:sortable")); ValuesParam mixinsExceptionParam = new ValuesParam(); mixinsExceptionParam.setName("mixinsCleanup.excludes"); mixinsExceptionParam.setValues(Collections.singletonList("exo:sortable;soc:profiledefinition")); initParams.addParam(workspaceParam); initParams.addParam(maxNodesToTreatParam); initParams.addParam(groupIdParam); initParams.addParam(mixinsParam); initParams.addParam(mixinsExceptionParam); return initParams; } private Session getSession() throws RepositoryException { PortalContainer container = PortalContainer.getInstance(); RepositoryService repositoryService = (RepositoryService) container.getComponentInstance(RepositoryService.class); ManageableRepository repository = repositoryService.getCurrentRepository(); return repository.getSystemSession("portal-test"); } }