project/com.nokia.carbide.cpp.epoc.engine.tests/src/com/nokia/carbide/cpp/epoc/engine/tests/model/TestViewDataCache.java
removing calls to ISymbianSDK#isEKA1(). For 3.0, EKA1 is not supported so any code returing true from isEKA1() is removed.
/*
* Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/
package com.nokia.carbide.cpp.epoc.engine.tests.model;
import com.nokia.carbide.cdt.builder.*;
import com.nokia.carbide.cpp.epoc.engine.model.*;
import com.nokia.carbide.cpp.epoc.engine.model.mmp.*;
import com.nokia.carbide.cpp.epoc.engine.preprocessor.DefineFactory;
import com.nokia.carbide.cpp.epoc.engine.preprocessor.IIncludeFileLocator;
import com.nokia.carbide.cpp.epoc.engine.tests.BaseTest;
import com.nokia.carbide.cpp.epoc.engine.tests.TestsPlugin;
import com.nokia.carbide.cpp.project.core.ProjectCorePlugin;
import com.nokia.carbide.internal.api.cpp.epoc.engine.preprocessor.BasicIncludeFileLocator;
import com.nokia.carbide.internal.cpp.epoc.engine.model.ViewDataCache;
import com.nokia.cpp.internal.api.utils.core.FileUtils;
import com.nokia.cpp.internal.api.utils.core.MultiResourceChangeListenerDispatcher;
import com.nokia.cpp.internal.api.utils.core.ProjectUtils;
import com.nokia.cpp.internal.api.utils.core.MultiResourceChangeListenerDispatcher.IResourceChangeHandler;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceDescription;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.resources.WorkspaceJob;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import java.io.File;
import java.util.ArrayList;
public class TestViewDataCache extends BaseTest {
/**
*
*/
private static final int TEST_TIME_MS = 7500;
private ViewDataCache<IMMPOwnedModel, IMMPModel, IMMPView, IMMPData> viewDataCache;
private IModelProvider modelProvider;
private File tmpDir;
private File projectDir;
// Try to wait long enough to ensure the timestamp-based check will detect a change
private static final long FS_TIME_RESOLUTION = FileUtils.getMinimumFileTimestampResolution(null);
/* (non-Javadoc)
* @see com.nokia.carbide.cpp.epoc.engine.tests.BaseTest#setUp()
*/
@SuppressWarnings("unchecked")
protected void setUp() throws Exception {
super.setUp();
modelProvider = ModelProviderFactory.createModelProvider(new MMPModelFactory());
viewDataCache = new ViewDataCache<IMMPOwnedModel, IMMPModel, IMMPView, IMMPData>(
modelProvider, 10);
tmpDir = new File(FileUtils.getTemporaryDirectory(), ""+System.currentTimeMillis());
tmpDir.mkdirs();
projectDir = tmpDir;
projectPath = new Path(tmpDir.getAbsolutePath());
}
/* (non-Javadoc)
* @see junit.framework.TestCase#tearDown()
*/
@Override
protected void tearDown() throws Exception {
super.tearDown();
FileUtils.delTree(tmpDir);
}
protected IPath makeFile(String relPath, String content) throws Exception {
File file = new File(tmpDir, relPath);
file.getParentFile().mkdirs();
FileUtils.writeFileContents(file, content.toCharArray(), null);
return new Path(file.getAbsolutePath());
}
public void testBasicNoProject() throws Exception {
IPath mmpPath = makeFile("group/foo.mmp",
"SOURCEPATH .\n"+
"SOURCE foo.cpp\n");
IMMPData data = viewDataCache.getData(mmpPath, new DefaultMMPViewConfiguration(projectPath));
assertNotNull(data);
assertEquals(1, data.getSources().size());
assertEquals(new Path("group/foo.cpp"), data.getSources().get(0));
IMMPData data2 = viewDataCache.getData(mmpPath, new DefaultMMPViewConfiguration(projectPath));
assertSame(data, data2);
// sanity check
IPath mmpPathBar = makeFile("group/bar.mmp",
"SOURCEPATH .\n"+
"SOURCE bar.cpp\n");
IMMPData dataBar = viewDataCache.getData(mmpPathBar, new DefaultMMPViewConfiguration(projectPath));
assertNotSame(data, dataBar);
}
public void testInvalidateToplevelFile() throws Exception {
IPath mmpPath = makeFile("group/foo.mmp",
"SOURCEPATH .\n"+
"SOURCE foo.cpp\n");
IMMPData data = viewDataCache.getData(mmpPath, new DefaultMMPViewConfiguration(projectPath));
assertNotNull(data);
assertEquals(1, data.getSources().size());
assertEquals(new Path("group/foo.cpp"), data.getSources().get(0));
// change foo.mmp on disk
Thread.sleep(FS_TIME_RESOLUTION);
makeFile("group/foo.mmp",
"SOURCEPATH .\n"+
"SOURCE foo.cpp bar.cpp\n"); // note: size changes too
// cache throttles file timestamp checks
Thread.sleep(FS_TIME_RESOLUTION);
IMMPData data2 = viewDataCache.getData(mmpPath, new DefaultMMPViewConfiguration(projectPath));
assertNotNull(data2);
assertNotSame(data, data2);
assertEquals(2, data2.getSources().size());
assertEquals(new Path("group/foo.cpp"), data2.getSources().get(0));
assertEquals(new Path("group/bar.cpp"), data2.getSources().get(1));
}
public void testInvalidateIncludeFile() throws Exception {
makeFile("group/header.mmh",
"BASEADDRESS 0x6000");
IPath mmpPath = makeFile("group/foo.mmp",
"#include \"header.mmh\"\n"+
"SOURCEPATH .\n"+
"SOURCE foo.cpp\n");
IMMPData data = viewDataCache.getData(mmpPath, new DefaultMMPViewConfiguration(projectPath));
assertNotNull(data);
assertEquals(1, data.getSources().size());
assertEquals(new Path("group/foo.cpp"), data.getSources().get(0));
assertEquals("0x6000", data.getSingleArgumentSettings().get(EMMPStatement.BASEADDRESS));
// change foo.mmh on disk
Thread.sleep(FS_TIME_RESOLUTION);
makeFile("group/header.mmh",
"BASEADDRESS 0x1111"); // note: size does not change
// cache throttles disk time checks
Thread.sleep(FS_TIME_RESOLUTION);
IMMPData data2 = viewDataCache.getData(mmpPath, new DefaultMMPViewConfiguration(projectPath));
assertNotNull(data2);
assertNotSame(data, data2);
assertEquals(1, data2.getSources().size());
assertEquals(new Path("group/foo.cpp"), data2.getSources().get(0));
assertEquals("0x1111", data2.getSingleArgumentSettings().get(EMMPStatement.BASEADDRESS));
IMMPData data3 = viewDataCache.getData(mmpPath, new DefaultMMPViewConfiguration(projectPath));
assertNotNull(data3);
assertSame(data3, data2);
}
public void testInvalidateMacros() throws Exception {
makeFile("group/header.mmh",
"BASEADDRESS 0x6000");
IPath mmpPath = makeFile("group/foo.mmp",
"#include \"header.mmh\"\n"+
"SOURCEPATH .\n"+
"SOURCE MYSOURCE\n");
DefaultMMPViewConfiguration viewConfig = new DefaultMMPViewConfiguration(projectPath);
viewConfig.getExtraMacros().add(DefineFactory.createSimpleFreeformDefine("MYSOURCE=foo.cpp"));
IMMPData data = viewDataCache.getData(mmpPath, viewConfig);
assertNotNull(data);
assertEquals(1, data.getSources().size());
assertEquals(new Path("group/foo.cpp"), data.getSources().get(0));
assertEquals("0x6000", data.getSingleArgumentSettings().get(EMMPStatement.BASEADDRESS));
// change macro
viewConfig = new DefaultMMPViewConfiguration(projectPath);
viewConfig.getExtraMacros().add(DefineFactory.createSimpleFreeformDefine("MYSOURCE=bar.cpp"));
IMMPData data2 = viewDataCache.getData(mmpPath, viewConfig);
assertNotNull(data2);
assertNotSame(data, data2);
assertEquals(1, data2.getSources().size());
assertEquals(new Path("group/bar.cpp"), data2.getSources().get(0));
assertEquals("0x6000", data2.getSingleArgumentSettings().get(EMMPStatement.BASEADDRESS));
// and no macros
viewConfig = new DefaultMMPViewConfiguration(projectPath);
IMMPData data3 = viewDataCache.getData(mmpPath, viewConfig);
assertNotNull(data3);
assertNotSame(data3, data2);
assertEquals(1, data3.getSources().size());
assertEquals(new Path("group/MYSOURCE"), data3.getSources().get(0));
assertEquals("0x6000", data3.getSingleArgumentSettings().get(EMMPStatement.BASEADDRESS));
}
public void testInvalidateMacros2() throws Exception {
IPath mmpPath = makeFile("group/foo.mmp",
"SOURCEPATH SOURCEDIR\n"+
"SOURCE MYSOURCE\n");
DefaultMMPViewConfiguration viewConfig = new DefaultMMPViewConfiguration(projectPath);
viewConfig.getExtraMacros().add(DefineFactory.createSimpleFreeformDefine("MYSOURCE=foo.cpp"));
viewConfig.getExtraMacros().add(DefineFactory.createSimpleFreeformDefine("SOURCEDIR=."));
IMMPData data = viewDataCache.getData(mmpPath, viewConfig);
assertNotNull(data);
assertEquals(1, data.getSources().size());
assertEquals(new Path("group/foo.cpp"), data.getSources().get(0));
// change macro order only
viewConfig = new DefaultMMPViewConfiguration(projectPath);
viewConfig.getExtraMacros().add(DefineFactory.createSimpleFreeformDefine("SOURCEDIR=."));
viewConfig.getExtraMacros().add(DefineFactory.createSimpleFreeformDefine("MYSOURCE=foo.cpp"));
IMMPData data2 = viewDataCache.getData(mmpPath, viewConfig);
assertNotNull(data2);
//assertSame(data, data2);
assertNotSame(data, data2); // don't waste time sorting macros
assertEquals(1, data2.getSources().size());
assertEquals(new Path("group/foo.cpp"), data2.getSources().get(0));
// now change macros
viewConfig = new DefaultMMPViewConfiguration(projectPath);
viewConfig.getExtraMacros().add(DefineFactory.createSimpleFreeformDefine("SOURCEDIR=.."));
viewConfig.getExtraMacros().add(DefineFactory.createSimpleFreeformDefine("MYSOURCE=out.cpp"));
IMMPData data3 = viewDataCache.getData(mmpPath, viewConfig);
assertNotNull(data3);
assertNotSame(data3, data2);
assertEquals(1, data3.getSources().size());
assertEquals(new Path("out.cpp"), data3.getSources().get(0));
}
public void testInvalidateIncludePaths() throws Exception {
makeFile("inc/header.mmh",
"BASEADDRESS 0x6000");
makeFile("alt/header.mmh",
"BASEADDRESS 0x1111");
IPath mmpPath = makeFile("group/foo.mmp",
"#include \"header.mmh\"\n"+
"SOURCEPATH .\n"+
"SOURCE foo.cpp\n");
IIncludeFileLocator mylocator1 = new BasicIncludeFileLocator(
new File[] { new File(projectDir, "inc") }, new File[0]);
IIncludeFileLocator mylocator2 = new BasicIncludeFileLocator(
new File[] { new File(projectDir, "alt") }, new File[0]);
DefaultMMPViewConfiguration viewConfig = new DefaultMMPViewConfiguration(projectPath);
((DefaultViewParserConfiguration) viewConfig.getViewParserConfiguration()).setIncludeFileLocator(mylocator1);
IMMPData data = viewDataCache.getData(mmpPath, viewConfig);
assertNotNull(data);
assertEquals(1, data.getSources().size());
assertEquals(new Path("group/foo.cpp"), data.getSources().get(0));
assertEquals("0x6000", data.getSingleArgumentSettings().get(EMMPStatement.BASEADDRESS));
// change include path order
viewConfig = new DefaultMMPViewConfiguration(projectPath);
((DefaultViewParserConfiguration) viewConfig.getViewParserConfiguration()).setIncludeFileLocator(mylocator2);
IMMPData data2 = viewDataCache.getData(mmpPath, viewConfig);
assertNotNull(data2);
assertNotSame(data, data2);
assertEquals(1, data2.getSources().size());
assertEquals(new Path("group/foo.cpp"), data2.getSources().get(0));
assertEquals("0x1111", data2.getSingleArgumentSettings().get(EMMPStatement.BASEADDRESS));
viewConfig = new DefaultMMPViewConfiguration(projectPath);
((DefaultViewParserConfiguration) viewConfig.getViewParserConfiguration()).setIncludeFileLocator(mylocator2);
IMMPData data3 = viewDataCache.getData(mmpPath, viewConfig);
assertNotNull(data3);
assertSame(data3, data2);
}
class ViewWriter {
private final IPath path;
private final IViewConfiguration config;
private final char token;
public ViewWriter(IPath path, IViewConfiguration config, char token) {
this.path = path;
this.config = config;
this.token = token;
}
public void doWork() {
try {
System.out.print(token);
// get the data from cache...
IMMPData data = viewDataCache.getData(path, config);
IMMPModel model = (IMMPModel) modelProvider.getSharedModel(path);
IMMPView view = model.createView(config);
if (data.getFlags().contains(EMMPStatement.DEBUGGABLE)) {
view.getFlags().remove(EMMPStatement.DEBUGGABLE);
} else {
view.getFlags().add(EMMPStatement.DEBUGGABLE);
}
try {
view.commit();
} catch (IllegalStateException e) {
view.revert();
}
} catch (CoreException e) {
throw new RuntimeException(e); // get me out of here
}
}
}
class ViewReader {
private final IPath path;
private final IViewConfiguration config;
private final char token;
public ViewReader(IPath path, IViewConfiguration config, char token) {
this.path = path;
this.config = config;
this.token = token;
}
public void doWork() {
System.out.print(token);
// get the data from cache...
IMMPData data;
try {
data = viewDataCache.getData(path, config);
data = viewDataCache.getData(path, config);
data = viewDataCache.getData(path, config);
data = viewDataCache.getData(path, config);
if (data != null) ; // read to squash warning
} catch (CoreException e) {
throw new RuntimeException(e);
}
}
}
class ViewWriterThread extends Thread {
private ViewWriter accessor;
private final int delay;
public ViewWriterThread(IPath path, IViewConfiguration config, char token, int delay) {
this.delay = delay;
accessor = new ViewWriter(path, config, token);
}
/* (non-Javadoc)
* @see java.lang.Thread#run()
*/
@Override
public void run() {
while (!isInterrupted()) {
accessor.doWork();
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
return;
}
}
}
}
class ViewWriterListener implements IResourceChangeHandler {
private ViewWriter accessor;
public ViewWriterListener(IPath path, IViewConfiguration config, char token) {
accessor = new ViewWriter(path, config, token);
}
/* (non-Javadoc)
* @see com.nokia.sdt.utils.MultiResourceChangeListenerDispatcher.IResourceChangeHandler#resourceChanged(org.eclipse.core.runtime.IPath)
*/
public void resourceChanged(IPath workspacePath) {
// write in a resource job
// (resource change listeners are not allowed to perform
// resource changes on the files they're listening to)
WorkspaceJob job = new WorkspaceJob("foo") {
@Override
public IStatus runInWorkspace(IProgressMonitor monitor)
throws CoreException {
accessor.doWork();
return Status.OK_STATUS;
}
};
job.setRule(FileUtils.convertFileToExistingResource(this.accessor.path.toFile()));
job.schedule();
}
}
class ViewReaderListener implements IResourceChangeHandler {
private ViewReader accessor;
public ViewReaderListener(IPath path, IViewConfiguration config, char token) {
accessor = new ViewReader(path, config, token);
}
/* (non-Javadoc)
* @see com.nokia.sdt.utils.MultiResourceChangeListenerDispatcher.IResourceChangeHandler#resourceChanged(org.eclipse.core.runtime.IPath)
*/
public void resourceChanged(IPath workspacePath) {
accessor.doWork();
}
}
/** Bug found while fixing bug 7882 -- view commits were synchronized, but not
* CREATING views, which also needed to be.
* @throws Exception
*/
public void testViewCommitThreading() throws Exception {
IPath mmpPath = makeFile("group/foo.mmp",
"SOURCEPATH .\n"+
"SOURCE foo.cpp\n"+
"\n"+
"TARGET foo.exe\n"+
"TARGETTYPE exe\n"+
"\n"+
"LIBRARY a b c\n");
IViewConfiguration config = new DefaultMMPViewConfiguration(projectPath);
long timeout = System.currentTimeMillis() + TEST_TIME_MS;
Thread a = new ViewWriterThread(mmpPath, config, 'a', 0);
Thread b = new ViewWriterThread(mmpPath, config, 'b', 0);
a.start();
b.start();
while (System.currentTimeMillis() < timeout) {
Thread.sleep(100);
}
a.interrupt();
b.interrupt();
System.out.println();
waitForThreads(a, b);
}
/**
* Bug found while fixing bug 7882: a resource listener which tries to commit a view would have
* parts of the model/view/cache set locked, while committing a view on another
* thread would have another set of objects locked in a different order, leading to deadlock.
* @throws Exception
*/
// XXX: EJS: this test fails sporadically and its fix or methodology needs more investigation. It did not directly reflect the bug fixed, so I don't know if it's really an issue.
public void UNSTABLE_testViewCommitResourceThreading() throws Exception {
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IWorkspaceDescription workspaceDesc = workspace.getDescription();
workspaceDesc.setAutoBuilding(false);
workspace.setDescription(workspaceDesc);
String projectName = "threading-viewcommit";
IProject project = ProjectCorePlugin.createProject(projectName, null);
ProjectCorePlugin.postProjectCreatedActions(project, "group/bld.inf", TestsPlugin.getUsableBuildConfigs(),
new ArrayList<String>(), "Debug MMP", null, new NullProgressMonitor());
projectPath = project.getLocation();
IPath mmpPath = projectPath.append("foo.mmp");
FileUtils.writeFileContents(mmpPath.toFile(),
("SOURCEPATH .\n"+
"SOURCE foo.cpp\n"+
"\n"+
"TARGET foo.exe\n"+
"TARGETTYPE exe\n"+
"\n"+
"LIBRARY a b c\n").toCharArray(), null);
project.refreshLocal(1, null);
IViewConfiguration config = new DefaultMMPViewConfiguration(projectPath);
long timeout = System.currentTimeMillis() + TEST_TIME_MS;
// listen to resource changes
MultiResourceChangeListenerDispatcher dispatcher1 = new MultiResourceChangeListenerDispatcher();
MultiResourceChangeListenerDispatcher dispatcher2 = new MultiResourceChangeListenerDispatcher();
try {
dispatcher1.addResource(FileUtils.convertToWorkspacePath(mmpPath),
new ViewWriterListener(
FileUtils.convertToWorkspaceLocation(mmpPath),
config, 'l'));
dispatcher2.addResource(FileUtils.convertToWorkspacePath(mmpPath),
new ViewWriterListener(
FileUtils.convertToWorkspaceLocation(mmpPath),
config, 'm'));
Thread a = new ViewWriterThread(mmpPath, config, 'a', 150);
Thread b = new ViewWriterThread(mmpPath, config, 'b', 50);
a.start();
b.start();
while (System.currentTimeMillis() < timeout) {
Thread.sleep(100);
}
a.interrupt();
b.interrupt();
System.out.println();
waitForThreads(a, b);
} finally {
dispatcher1.removeAll();
dispatcher2.removeAll();
}
// do this outside the finally -- else the resources held by
// possibly deadlocked threads prevent it from finishing
ProjectUtils.closeAndDeleteProject(projectName);
}
/**
* Bug 7882: when a view committed, it immediately alerted listeners (including the
* model provider), which kept the model/view locked while trying to save.
* A resource listener paying attention to this would try to read the view data
* cache, but since the model just changed, it would need to recreate the view.
* In this case, there are two threads locked on the model/view and view data cache.
* <p>
* We can break the cache lock. We had it in order to avoid rereading the data
* into the cache twice. But we sacrifice that to avoid a deadlock. The other
* tests above address the other deadlocks that could arise from simultaneous commits.
* @throws Exception
*/
public void testViewDataThreading() throws Exception {
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IWorkspaceDescription workspaceDesc = workspace.getDescription();
workspaceDesc.setAutoBuilding(false);
workspace.setDescription(workspaceDesc);
String projectName = "threading-viewdatacache";
IProject project = ProjectCorePlugin.createProject(projectName, null);
ProjectCorePlugin.postProjectCreatedActions(project, "group/bld.inf", TestsPlugin.getUsableBuildConfigs(),
new ArrayList<String>(), "Debug MMP", null, new NullProgressMonitor());
projectPath = project.getLocation();
IPath mmpPath = projectPath.append("foo.mmp");
FileUtils.writeFileContents(mmpPath.toFile(),
("SOURCEPATH .\n"+
"SOURCE foo.cpp\n"+
"\n"+
"TARGET foo.exe\n"+
"TARGETTYPE exe\n"+
"\n"+
"LIBRARY a b c\n").toCharArray(), null);
project.refreshLocal(1, null);
IViewConfiguration config = new DefaultMMPViewConfiguration(projectPath);
long timeout = System.currentTimeMillis() + TEST_TIME_MS;
// listen to resource changes
MultiResourceChangeListenerDispatcher dispatcher1 = new MultiResourceChangeListenerDispatcher();
MultiResourceChangeListenerDispatcher dispatcher2 = new MultiResourceChangeListenerDispatcher();
try {
dispatcher1.addResource(FileUtils.convertToWorkspacePath(mmpPath),
new ViewReaderListener(
FileUtils.convertToWorkspaceLocation(mmpPath),
config, 'r'));
dispatcher2.addResource(FileUtils.convertToWorkspacePath(mmpPath),
new ViewReaderListener(
FileUtils.convertToWorkspaceLocation(mmpPath),
config, 's'));
Thread a = new ViewWriterThread(mmpPath, config, 'a', 150);
Thread b = new ViewWriterThread(mmpPath, config, 'b', 50);
a.start();
b.start();
while (System.currentTimeMillis() < timeout) {
Thread.sleep(100);
}
a.interrupt();
b.interrupt();
System.out.println();
waitForThreads(a, b);
} finally {
dispatcher1.removeAll();
dispatcher2.removeAll();
}
// do this outside the finally -- else the resources held by
// possibly deadlocked threads prevent it from finishing
ProjectUtils.closeAndDeleteProject(projectName);
}
/**
* @param a
* @param b
*/
private void waitForThreads(Thread a, Thread b) throws Exception {
a.join(5000);
b.join(5000);
if (a.isAlive() || b.isAlive()) {
fail("Threads deadlocked");
}
}
}