blob: 66e008f850477b137e281a2056b29ba6dab286a6 [file] [log] [blame]
/*
* Copyright (c) 2019 Eike Stepper (Loehne, Germany) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Eike Stepper - initial API and implementation
*/
package org.eclipse.emf.cdo.tests.bugzilla;
import org.eclipse.emf.cdo.common.CDOCommonSession.Options.PassiveUpdateMode;
import org.eclipse.emf.cdo.common.branch.CDOBranch;
import org.eclipse.emf.cdo.common.protocol.CDOProtocol.CommitNotificationInfo;
import org.eclipse.emf.cdo.common.revision.CDORevision;
import org.eclipse.emf.cdo.internal.server.SessionManager;
import org.eclipse.emf.cdo.session.CDOSession;
import org.eclipse.emf.cdo.spi.server.ICommitConflictResolver;
import org.eclipse.emf.cdo.tests.AbstractCDOTest;
import org.eclipse.emf.cdo.tests.config.IRepositoryConfig;
import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.CleanRepositoriesAfter;
import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.CleanRepositoriesBefore;
import org.eclipse.emf.cdo.tests.config.impl.RepositoryConfig;
import org.eclipse.emf.cdo.tests.model1.Company;
import org.eclipse.emf.cdo.transaction.CDOTransaction;
import org.eclipse.emf.cdo.util.CDOUtil;
import org.eclipse.emf.internal.cdo.session.CDOTransactionContainerImpl.TransactionCreator;
import org.eclipse.emf.internal.cdo.transaction.CDOTransactionImpl;
import org.eclipse.net4j.util.io.IOUtil;
import org.eclipse.emf.spi.cdo.InternalCDOTransaction;
import java.util.ArrayList;
import java.util.List;
/**
* Bug 547640 - Support server-side commit conflict resolution.
*
* @author Eike Stepper
*/
@CleanRepositoriesBefore(reason = "server-side merging")
@CleanRepositoriesAfter(reason = "server-side merging")
public class Bugzilla_547640_Test extends AbstractCDOTest
{
@Requires(IRepositoryConfig.CAPABILITY_AUDITING)
public void testCommitConflictResolver_OneCommit() throws Exception
{
run(new TestLogic()
{
private int expectedVersion;
public void modifyAndCommit1(CDOTransaction transaction, Company company) throws Exception
{
company.getCategories().add(getModel1Factory().createCategory());
transaction.commit();
expectedVersion = CDOUtil.getCDOObject(company).cdoRevision().getVersion() + 1;
}
public void modify2(CDOTransaction transaction, Company company) throws Exception
{
company.getCategories().add(getModel1Factory().createCategory());
}
public void verify2(CDOTransaction transaction, Company company) throws Exception
{
CDORevision cdoRevision = CDOUtil.getCDOObject(company).cdoRevision();
assertEquals(expectedVersion, cdoRevision.getVersion());
assertEquals(2, company.getCategories().size());
}
});
}
@Requires(IRepositoryConfig.CAPABILITY_AUDITING)
public void testCommitConflictResolver_TwoCommits() throws Exception
{
run(new TestLogic()
{
private int expectedVersion;
public void modifyAndCommit1(CDOTransaction transaction, Company company) throws Exception
{
company.getCategories().add(getModel1Factory().createCategory());
transaction.commit();
company.getCategories().add(getModel1Factory().createCategory());
transaction.commit();
expectedVersion = CDOUtil.getCDOObject(company).cdoRevision().getVersion() + 1;
}
public void modify2(CDOTransaction transaction, Company company) throws Exception
{
company.getCategories().add(getModel1Factory().createCategory());
}
public void verify2(CDOTransaction transaction, Company company) throws Exception
{
CDORevision cdoRevision = CDOUtil.getCDOObject(company).cdoRevision();
assertEquals(expectedVersion, cdoRevision.getVersion());
}
});
}
@Override
protected void doSetUp() throws Exception
{
super.doSetUp();
getTestProperties().put(RepositoryConfig.PROP_TEST_COMMIT_CONFLICT_RESOLVER, new ICommitConflictResolver.Merging());
getTestProperties().put(RepositoryConfig.PROP_TEST_SESSION_MANAGER, new SuspendableSessionManager());
}
@Override
protected void doTearDown() throws Exception
{
TransactionCreator.reset();
super.doTearDown();
}
protected SuspendableSessionManager getSessionManager()
{
return (SuspendableSessionManager)getTestProperties().get(RepositoryConfig.PROP_TEST_SESSION_MANAGER);
}
private void run(final TestLogic testLogic) throws Exception
{
CDOSession session1 = openSession();
CDOTransaction transaction1 = session1.openTransaction();
Company company1 = getModel1Factory().createCompany();
transaction1.createResource(getResourcePath("resource")).getContents().add(company1);
transaction1.commit();
CDOSession session2 = openSession();
session2.options().setPassiveUpdateMode(PassiveUpdateMode.CHANGES);
TransactionCreator.set(new TransactionCreator()
{
@Override
public InternalCDOTransaction createTransaction(CDOSession session, CDOBranch branch)
{
return new CDOTransactionImpl(session, branch)
{
@Override
protected void waitForBaseline(long previousTimeStamp)
{
getSessionManager().resume();
super.waitForBaseline(previousTimeStamp);
}
};
}
});
final CDOTransaction transaction2 = session2.openTransaction();
TransactionCreator.reset();
final Company company2 = (Company)transaction2.getResource(getResourcePath("resource")).getContents().get(0);
// Let client2 modify the model (but not commit, yet).
testLogic.modify2(transaction2, company2);
// Let client1 modify the model and commit (but hold back commit notifications to client2).
getSessionManager().suspend();
testLogic.modifyAndCommit1(transaction1, company1);
// Let client2 commit and verify the result.
transaction2.commit();
testLogic.verify2(transaction2, company2);
}
/**
* @author Eike Stepper
*/
private static class SuspendableSessionManager extends SessionManager
{
private List<CommitNotificationInfo> queue;
public synchronized void suspend()
{
IOUtil.OUT().println("Suspending commit notifications");
queue = new ArrayList<CommitNotificationInfo>();
}
public synchronized void resume()
{
IOUtil.OUT().println("Resuming commit notifications");
try
{
for (CommitNotificationInfo info : queue)
{
super.sendCommitNotification(info);
}
}
finally
{
queue = null;
}
}
@Override
public synchronized void sendCommitNotification(CommitNotificationInfo info)
{
if (queue != null)
{
queue.add(info);
}
else
{
super.sendCommitNotification(info);
}
}
}
/**
* @author Eike Stepper
*/
public interface TestLogic
{
public void modifyAndCommit1(CDOTransaction transaction, Company company) throws Exception;
public void modify2(CDOTransaction transaction, Company company) throws Exception;
public void verify2(CDOTransaction transaction, Company company) throws Exception;
}
}