/******************************************************************************* * Copyright (c) 2004, 2015 Tasktop Technologies 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: * Tasktop Technologies - initial API and implementation *******************************************************************************/ package org.eclipse.mylyn.context.tests; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.util.Scanner; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import org.eclipse.mylyn.commons.sdk.util.CommonTestUtil; import org.eclipse.mylyn.context.core.AbstractContextContributor; import org.eclipse.mylyn.context.core.ContextCore; import org.eclipse.mylyn.context.core.IInteractionContext; import org.eclipse.mylyn.context.core.IInteractionContextScaling; import org.eclipse.mylyn.context.core.IInteractionElement; import org.eclipse.mylyn.context.core.IInteractionRelation; import org.eclipse.mylyn.context.tests.support.DomContextReader; import org.eclipse.mylyn.context.tests.support.DomContextWriter; import org.eclipse.mylyn.internal.context.core.ContextCorePlugin; import org.eclipse.mylyn.internal.context.core.InteractionContext; import org.eclipse.mylyn.internal.context.core.InteractionContextExternalizer; import org.eclipse.mylyn.internal.context.core.InteractionContextManager; import org.eclipse.mylyn.internal.context.core.SaxContextReader; import org.eclipse.mylyn.internal.context.core.SaxContextWriter; import org.eclipse.mylyn.monitor.core.InteractionEvent; /** * @author Mik Kersten * @author Shawn Minto */ public class ContextExternalizerTest extends AbstractContextTest { private static final String CONTEXT_HANDLE = "context-externalization"; private InteractionContext context; private IInteractionContextScaling scaling; private File contextFile; private AbstractContextContributor contributor; @Override protected void setUp() throws Exception { super.setUp(); scaling = ContextCore.getCommonContextScaling(); context = new InteractionContext(CONTEXT_HANDLE, ContextCore.getCommonContextScaling()); assertNotNull(ContextCore.getContextManager()); } @Override protected void tearDown() throws Exception { if (contextFile != null && contextFile.exists()) { contextFile.delete(); } if (contributor != null) { ContextCorePlugin.getDefault().removeContextContributor(contributor); } super.tearDown(); } public void testContentAttributeExternalization() throws Exception { InteractionContextExternalizer externalizer = new InteractionContextExternalizer(); context.parseEvent(mockSelection("1")); context.setContentLimitedTo("foobar"); IInteractionContext loaded = writeAndReadContext(context, externalizer); assertEquals("foobar", loaded.getContentLimitedTo()); } public void testSaxExternalizationAgainstDom() throws Exception { File file = CommonTestUtil.getFile(this, "testdata/externalizer/testcontext.xml.zip"); assertTrue(file.getAbsolutePath(), file.exists()); InteractionContextExternalizer externalizer = new InteractionContextExternalizer(); IInteractionContext domReadContext = externalizer.readContextFromXml(CONTEXT_HANDLE, file, new DomContextReader(), scaling); IInteractionContext saxReadContext = externalizer.readContextFromXml(CONTEXT_HANDLE, file, new SaxContextReader(), scaling); assertEquals(284, saxReadContext.getInteractionHistory().size()); // known from testdata assertEquals(domReadContext, saxReadContext); File domOut = new File("dom-out.xml"); domOut.deleteOnExit(); externalizer.writeContextToXml(saxReadContext, domOut, new DomContextWriter()); File saxOut = new File("sax-out.xml"); saxOut.deleteOnExit(); externalizer.writeContextToXml(domReadContext, saxOut, new SaxContextWriter()); IInteractionContext domReadAfterWrite = externalizer.readContextFromXml(CONTEXT_HANDLE, saxOut, new DomContextReader(), scaling); IInteractionContext saxReadAfterWrite = externalizer.readContextFromXml(CONTEXT_HANDLE, domOut, new SaxContextReader(), scaling); assertEquals(domReadAfterWrite, saxReadAfterWrite); } public void testContextSize() throws Exception { InteractionContextExternalizer externalizer = new InteractionContextExternalizer(); String path = "extern.xml"; File file = new File(path); file.deleteOnExit(); int ORIGINAL = 100; for (int i = 0; i < ORIGINAL; i++) { context.parseEvent(mockSelection("1")); context.parseEvent(mockPreferenceChange("2")); } context.collapse(); externalizer.writeContextToXml(context, file); long size = file.length(); context.reset(); for (int i = 0; i < ORIGINAL * ORIGINAL; i++) { context.parseEvent(mockSelection("1")); context.parseEvent(mockPreferenceChange("2")); } context.collapse(); externalizer.writeContextToXml(context, file); long size2 = file.length(); assertTrue(size <= size2 * 2); } public void testExternalization() throws Exception { InteractionContextExternalizer externalizer = new InteractionContextExternalizer(); IInteractionElement node = context.parseEvent(mockSelection("1")); context.parseEvent(mockNavigation("2")); IInteractionRelation edge = node.getRelation("2"); assertNotNull(edge); assertEquals(1, node.getRelations().size()); context.parseEvent(mockInterestContribution("3", scaling.getLandmark() + scaling.getDecay() * 3)); assertTrue("interest: " + context.get("3").getInterest().getValue(), context.get("3") .getInterest() .isLandmark()); float doi = node.getInterest().getValue(); assertNotNull(context.getLandmarks()); // "3" not a user event assertEquals("2", context.getActiveNode().getHandleIdentifier()); IInteractionContext loaded = writeAndReadContext(context, externalizer); assertEquals(3, loaded.getInteractionHistory().size()); IInteractionElement loadedNode = loaded.get("1"); IInteractionRelation edgeNode = loadedNode.getRelation("2"); assertNotNull(edgeNode); assertEquals(1, loadedNode.getRelations().size()); IInteractionElement landmark = loaded.get("3"); assertNotNull(loadedNode); assertEquals(doi, loadedNode.getInterest().getValue()); assertTrue(landmark.getInterest().isLandmark()); assertNotNull(loaded.getLandmarks()); assertEquals("2", loaded.getActiveNode().getHandleIdentifier()); } /** * What is written and read from disk should always return the same doi for an element when the context is collapsed * * @throws Exception */ public void testExternalizationWithCollapse() throws Exception { InteractionContextExternalizer externalizer = new InteractionContextExternalizer(); // create nodes in the context and ensure that writing and reading work properly IInteractionElement node1 = context.parseEvent(mockSelection("1")); IInteractionElement node2 = context.parseEvent(mockSelection("2")); context.parseEvent(mockSelection("2")); context.parseEvent(mockSelection("2")); float doi1 = node1.getInterest().getValue(); float doi2 = node2.getInterest().getValue(); int numEvents = context.getUserEventCount(); // key to this test context.collapse(); InteractionContext loadedContext = (InteractionContext) writeAndReadContext(context, externalizer); assertEquals(numEvents, loadedContext.getUserEventCount()); IInteractionElement loadedNode1 = loadedContext.get("1"); IInteractionElement loadedNode2 = loadedContext.get("2"); assertEquals(doi1, loadedNode1.getInterest().getValue()); assertEquals(doi2, loadedNode2.getInterest().getValue()); // // try to write a second time without changes // // key to this test loadedContext.collapse(); InteractionContext loadedContext2 = (InteractionContext) writeAndReadContext(loadedContext, externalizer); assertEquals(numEvents, loadedContext2.getUserEventCount()); loadedNode1 = loadedContext2.get("1"); loadedNode2 = loadedContext2.get("2"); assertEquals(doi1, loadedNode1.getInterest().getValue()); assertEquals(doi2, loadedNode2.getInterest().getValue()); // // try to change the context that was read and write again // node1 = loadedContext2.parseEvent(mockSelection("1")); node2 = loadedContext2.parseEvent(mockSelection("2")); loadedContext2.parseEvent(mockSelection("2")); loadedContext2.parseEvent(mockSelection("1")); doi1 = node1.getInterest().getValue(); doi2 = node2.getInterest().getValue(); numEvents = loadedContext2.getUserEventCount(); loadedContext2.collapse(); InteractionContext loadedContext3 = (InteractionContext) writeAndReadContext(loadedContext2, externalizer); assertEquals(numEvents, loadedContext3.getUserEventCount()); loadedNode1 = loadedContext3.get("1"); loadedNode2 = loadedContext3.get("2"); assertEquals(doi1, loadedNode1.getInterest().getValue()); assertEquals(doi2, loadedNode2.getInterest().getValue()); } private IInteractionContext writeAndReadContext(InteractionContext contextToWrite, InteractionContextExternalizer externalizer) throws Exception { File file = ContextCorePlugin.getContextStore().getFileForContext(contextToWrite.getHandleIdentifier()); file.deleteOnExit(); externalizer.writeContextToXml(contextToWrite, file); // TODO: fix up directory refs File dataDirectory = ContextCorePlugin.getContextStore().getContextDirectory().getParentFile(); File contextsDirectory = new File(dataDirectory, "contexts"/*WorkspaceAwareContextStore.CONTEXTS_DIRECTORY*/); File zippedContextFile = new File(contextsDirectory, contextToWrite.getHandleIdentifier() + InteractionContextManager.CONTEXT_FILE_EXTENSION); assertTrue(zippedContextFile.exists()); IInteractionContext loaded = externalizer.readContextFromXml(CONTEXT_HANDLE, zippedContextFile, scaling); assertNotNull(loaded); return loaded; } public void testReadOtherContextHandle() throws Exception { InteractionContextExternalizer externalizer = new InteractionContextExternalizer(); context.setHandleIdentifier("handle-1"); context.parseEvent(mockSelection("1")); File file1 = File.createTempFile("context", null); file1.deleteOnExit(); externalizer.writeContextToXml(context, file1); context.setHandleIdentifier("handle-2"); context.parseEvent(mockSelection("2")); File file2 = File.createTempFile("context", null); file2.deleteOnExit(); externalizer.writeContextToXml(context, file2); context = (InteractionContext) externalizer.readContextFromXml("handle-1", file1, scaling); assertNotNull(context); assertEquals(1, context.getAllElements().size()); context = (InteractionContext) externalizer.readContextFromXml("handle-1", file2, scaling); assertNotNull(context); assertEquals(2, context.getAllElements().size()); context = (InteractionContext) externalizer.readContextFromXml("abc", file1, scaling); assertNotNull(context); assertEquals(1, context.getAllElements().size()); } public void testReadInvalidContextHandle() throws Exception { InteractionContextExternalizer externalizer = new InteractionContextExternalizer(); File file = File.createTempFile("context", null); file.deleteOnExit(); ZipOutputStream out = new ZipOutputStream(new FileOutputStream(file)); try { ZipEntry entry = new ZipEntry("name"); out.putNextEntry(entry); } finally { out.close(); } context = (InteractionContext) externalizer.readContextFromXml("abc", file, scaling); assertNull(context); } public void testAddContextContributor() throws Exception { InteractionContextExternalizer externalizer = new InteractionContextExternalizer(); ContextCorePlugin contextCorePlugin = ContextCorePlugin.getDefault(); contributor = mock(AbstractContextContributor.class); when(contributor.getDataAsStream(context)).thenReturn(null); int initialContributor = contextCorePlugin.getContextContributor().size(); contextCorePlugin.addContextContributor(contributor); assertEquals(initialContributor + 1, contextCorePlugin.getContextContributor().size()); assertEquals(contributor, contextCorePlugin.getContextContributor().get(initialContributor)); externalizer.writeContext(context, mock(ZipOutputStream.class)); verify(contributor).getDataAsStream(context); contextCorePlugin.removeContextContributor(contributor); assertEquals(initialContributor, contextCorePlugin.getContextContributor().size()); } public void testWriteAdditionalContextData() throws Exception { InteractionContextExternalizer externalizer = new InteractionContextExternalizer(); contributor = mock(AbstractContextContributor.class); InteractionEvent event = mockNavigation("InteractionEvent"); context.parseEvent(event); String testContributorId = "myContributor"; String testData = "important context information"; InputStream testStream = new ByteArrayInputStream(testData.getBytes()); when(contributor.getIdentifier()).thenReturn(testContributorId); when(contributor.getDataAsStream(context)).thenReturn(testStream); ContextCorePlugin.getDefault().addContextContributor(contributor); contextFile = ContextCorePlugin.getContextStore().getFileForContext(context.getHandleIdentifier()); externalizer.writeContextToXml(context, contextFile); InputStream resultStream = externalizer.getAdditionalInformation(contextFile, testContributorId); assertNotNull(resultStream); assertNull(externalizer.getAdditionalInformation(contextFile, "nonExistingContributor")); assertEquals(testData, new Scanner(resultStream).useDelimiter("\\A").next()); resultStream = ContextCore.getContextManager().getAdditionalContextData(context, testContributorId); assertNotNull(resultStream); assertNull(externalizer.getAdditionalInformation(contextFile, "nonExistingContributor")); } }