/*
* 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");
}
}