/*
* JBoss, Home of Professional Open Source.
*
* See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing.
*
* See the AUTHORS.txt file distributed with this work for a full listing of individual contributors.
*/
package org.teiid.designer.vdb;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNull.notNullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
import static org.teiid.designer.vdb.Vdb.Event.DESCRIPTION;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Set;
import java.util.zip.Checksum;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.hamcrest.core.IsSame;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.teiid.core.designer.EclipseMock;
import org.teiid.core.designer.util.ChecksumUtil;
import org.teiid.core.designer.util.FileUtils;
import org.teiid.core.util.SmartTestDesignerSuite;
import org.teiid.designer.core.ModelWorkspaceMock;
import org.teiid.designer.core.util.VdbHelper.VdbFolders;
import org.teiid.designer.core.workspace.MockFileBuilder;
import org.teiid.designer.core.workspace.ModelUtil;
import org.teiid.designer.roles.DataRole;
import org.teiid.designer.runtime.version.spi.TeiidServerVersion.Version;
import org.teiid.designer.vdb.VdbEntry.Synchronization;
import org.teiid.designer.vdb.VdbFileEntry.FileEntryType;
import org.teiid.designer.vdb.file.ValidationVersionCallback;
import org.teiid.designer.vdb.file.VdbFileProcessor;
import org.teiid.designer.vdb.manifest.EntryElement;
import org.teiid.designer.vdb.manifest.ModelElement;
import org.teiid.designer.vdb.manifest.PropertyElement;
import org.teiid.designer.vdb.manifest.VdbElement;
/**
*
*/
@SuppressWarnings( "javadoc" )
public class VdbTest implements VdbConstants {
private Vdb vdb;
private EclipseMock eclipseMock;
private ModelWorkspaceMock modelWorkspaceMock;
@Mock
private IFile vdbFile;
@Before
public void before() throws Exception {
initMocks(this);
final IPath vdbPathAbsolute = mock(IPath.class);
when(vdbFile.getLocation()).thenReturn(vdbPathAbsolute);
/*
* Vdb uses this tempDir for creating temp archive then uses
* File.renameTo which seems to require that both files are in
* the same directory.
*/
File tempDir = VdbPlugin.singleton().getStateLocation().toFile();
final File vdbFileAbsolute = File.createTempFile(VdbTest.class.getSimpleName(), ".vdb", tempDir);
vdbFileAbsolute.deleteOnExit();
when(vdbPathAbsolute.toFile()).thenReturn(vdbFileAbsolute);
final IPath vdbName = mock(IPath.class);
when(vdbName.toString()).thenReturn(vdbFileAbsolute.getName());
when(vdbName.lastSegment()).thenReturn(FileUtils.getFilenameWithoutExtension(vdbFileAbsolute.getName()));
final IPath vdbPath = mock(IPath.class);
when(vdbPath.getFileExtension()).thenReturn("vdb");
when(vdbPath.removeFileExtension()).thenReturn(vdbName);
when(vdbPath.makeRelativeTo(isA(IPath.class))).thenReturn(vdbPath);
when(vdbFile.getFullPath()).thenReturn(vdbPath);
when(vdbFile.findMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE)).thenReturn(new IMarker[0]);
eclipseMock = new EclipseMock();
when(eclipseMock.workspaceRoot().findMember(vdbPath)).thenReturn(vdbFile);
modelWorkspaceMock = new ModelWorkspaceMock(eclipseMock);
vdb = new XmiVdb(vdbFile);
}
@After
public void after() throws Exception {
// Disposes the eclipse mock as well
modelWorkspaceMock.dispose();
modelWorkspaceMock = null;
eclipseMock = null;
}
/**
* @return eclipseMock
*/
EclipseMock getEclipseMock() {
return eclipseMock;
}
/**
* @return vdb
*/
Vdb getVdb() {
return vdb;
}
@Test
public void shouldBeModifiedWhenDescriptionChanges() throws Exception {
vdb.setDescription("new description");
assertThat(vdb.isModified(), is(true));
}
@Test
public void shouldBeModifiedWhenEntryIsAdded() throws Exception {
MockFileBuilder fileBuilder = new MockFileBuilder("Test", "txt");
vdb.addEntry(fileBuilder.getPath());
assertThat(vdb.isModified(), is(true));
}
@Test
public void shouldBeSynchronizedAfterAddingEntry() throws Exception {
MockFileBuilder fileBuilder = new MockFileBuilder("Test", "txt");
vdb.addEntry(fileBuilder.getPath());
assertThat(vdb.isSynchronized(), is(true));
}
@Test
public void shouldBeUnmodifiedAfterDescriptionChangesFromNullToEmpty() throws Exception {
vdb.setDescription(" ");
assertThat(vdb.isModified(), is(false));
}
@Test
public void shouldBeUnmodifiedAfterSave() throws Exception {
// when(vdb.getFile().findMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE)).thenReturn(new IMarker[0]);
// when(vdb.getFile().createMarker(IMarker.PROBLEM)).thenReturn(mock(IMarker.class));
vdb.setDescription("new description");
vdb.save();
assertThat(vdb.isModified(), is(false));
}
@Test
public void shouldExposeFile() throws Exception {
assertThat(vdb.getSourceFile(), is(vdbFile));
}
@Test
public void shouldExposeNameAsFileName() throws Exception {
assertThat(vdb.getSourceFile().getFullPath(), is(vdbFile.getFullPath()));
}
@Test
public void shouldInitiallyBeSynchronized() throws Exception {
assertThat(vdb.isSynchronized(), is(true));
}
@Test
public void shouldInitiallyBeUnmodified() throws Exception {
assertThat(vdb.isModified(), is(false));
}
@Test
public void shouldNeverReturnNullForEntries() throws Exception {
assertThat(vdb.getEntries(), notNullValue());
assertThat(vdb.getModelEntries(), notNullValue());
}
@Test
public void shouldNotifyAfterChangingDescription() throws Exception {
// set an initial description
final String oldDescription = "oldDescription";
vdb.setDescription(oldDescription);
// hookup listener
final PropertyChangeListener listener = mock(PropertyChangeListener.class);
vdb.addChangeListener(listener);
// change description
final String newDescription = "newDescription";
vdb.setDescription("newDescription");
// tests
final ArgumentCaptor<PropertyChangeEvent> arg = ArgumentCaptor.forClass(PropertyChangeEvent.class);
verify(listener).propertyChange(arg.capture());
assertThat(arg.getValue().getPropertyName(), is(DESCRIPTION));
assertThat((String)arg.getValue().getOldValue(), is(oldDescription));
assertThat((String)arg.getValue().getNewValue(), is(newDescription));
}
@Test
public void shouldNotNotifyAfterRemovingListener() throws Exception {
final PropertyChangeListener listener = mock(PropertyChangeListener.class);
vdb.addChangeListener(listener);
vdb.setDescription("test");
final ArgumentCaptor<PropertyChangeEvent> arg = ArgumentCaptor.forClass(PropertyChangeEvent.class);
verify(listener).propertyChange(arg.capture());
assertThat(arg.getValue().getPropertyName(), is(DESCRIPTION));
vdb.removeChangeListener(listener);
vdb.setDescription("test1");
verify(listener).propertyChange(isA(PropertyChangeEvent.class));
}
@Test
public void shouldNotNotifyAfterSettingDescriptionToSameValue() throws Exception {
final PropertyChangeListener listener = mock(PropertyChangeListener.class);
vdb.addChangeListener(listener);
vdb.setDescription("test");
final ArgumentCaptor<PropertyChangeEvent> arg = ArgumentCaptor.forClass(PropertyChangeEvent.class);
verify(listener).propertyChange(arg.capture());
assertThat(arg.getValue().getPropertyName(), is(DESCRIPTION));
vdb.setDescription("test");
verify(listener).propertyChange(isA(PropertyChangeEvent.class));
}
@Test
public void shouldNotNotifyIfAlreadySynchronized() throws Exception {
final PropertyChangeListener listener = mock(PropertyChangeListener.class);
vdb.addChangeListener(listener);
vdb.synchronize();
verify(listener, never()).propertyChange(isA(PropertyChangeEvent.class));
}
@Test
public void shouldNotRequireMonitorToAddEntry() throws Exception {
MockFileBuilder fileBuilder = new MockFileBuilder("Test", "txt");
vdb.addEntry(fileBuilder.getPath());
}
@Test
public void shouldNotRequireMonitorToSynchronize() throws Exception {
vdb.synchronize();
}
@Test
public void shouldReflectAddedAndRemovedEntries() throws Exception {
MockFileBuilder fileBuilder = new MockFileBuilder("Test", "txt");
final VdbEntry entry = vdb.addEntry(fileBuilder.getPath());
assertThat(vdb.getEntries().size(), is(1));
vdb.removeEntry(entry);
assertThat(vdb.getEntries().isEmpty(), is(true));
}
@Test
public void shouldReflectChangedDescription() throws Exception {
vdb.setDescription("test");
assertThat(vdb.getDescription(), is("test"));
}
@Test
public void shouldReturnExistingEntryWhenAddingDuplicateEntry() throws Exception {
final IPath path = new Path("/my/full/path");
final VdbEntry thisEntry = vdb.addEntry(path);
final VdbEntry thatEntry = vdb.addEntry(path);
assertThat(thatEntry, IsSame.sameInstance(thisEntry));
}
@Test
public void testAddingAndRemovingImportVdbEntry() throws Exception {
String entryName = "testImportVdbEntry";
vdb.addImport(entryName, "1");
Collection<VdbImportVdbEntry> entries = vdb.getImports();
assertEquals(1, entries.size());
VdbImportVdbEntry entry = entries.iterator().next();
assertEquals(entryName, entry.getName());
vdb.removeImport(entry);
assertEquals(0, vdb.getImports().size());
}
@Test
public void testOpeningExistingVdb() throws Exception {
Vdb booksVdb = VdbTestUtils.mockBooksVdb(modelWorkspaceMock);
assertEquals("Books_2120", booksVdb.getName());
assertEquals(VdbTestUtils.BOOKS_VDB_FILE.getCanonicalPath(), booksVdb.getSourceFile().getLocation().toOSString());
assertEquals(2, booksVdb.getModelEntries().size());
assertEquals(2, booksVdb.getSchemaEntries().size());
assertEquals(0, booksVdb.getUdfJarEntries().size());
assertEquals(0, booksVdb.getUserFileEntries().size());
for (VdbEntry modelEntry : booksVdb.getModelEntries()) {
assertEquals(Synchronization.Synchronized, modelEntry.getSynchronization());
assertTrue(((VdbModelEntry)modelEntry).getIndexFile().exists());
/* Get the expected index file from the test data directory */
File expIdxFile = SmartTestDesignerSuite.getTestDataFile(getClass(),
VdbTestUtils.BOOKS_VDB_PROJECT + File.separator +
VdbTestUtils.RUNTIME_INF + File.separator +
((VdbModelEntry)modelEntry).getIndexName());
assertTrue(expIdxFile.exists());
/* Compare the checksums of the created index file and the expected index file */
FileInputStream fis1 = new FileInputStream(((VdbModelEntry)modelEntry).getIndexFile());
FileInputStream fis2 = new FileInputStream(expIdxFile);
Checksum idxChksum = ChecksumUtil.computeChecksum(fis1);
Checksum expChksum = ChecksumUtil.computeChecksum(fis2);
assertEquals(expChksum.getValue(), idxChksum.getValue());
fis1.close();
fis2.close();
}
for (VdbSchemaEntry schemaEntry : booksVdb.getSchemaEntries()) {
assertEquals(Synchronization.Synchronized, schemaEntry.getSynchronization());
assertTrue(schemaEntry.getIndexFile().exists());
/* Get the expected index file from the test data directory */
File expIdxFile = SmartTestDesignerSuite.getTestDataFile(getClass(),
VdbTestUtils.BOOKS_VDB_PROJECT + File.separator +
VdbTestUtils.RUNTIME_INF + File.separator +
schemaEntry.getIndexName());
assertTrue(expIdxFile.exists());
/* Compare the checksums of the created index file and the expected index file */
FileInputStream fis1 = new FileInputStream(schemaEntry.getIndexFile());
FileInputStream fis2 = new FileInputStream(expIdxFile);
Checksum idxChksum = ChecksumUtil.computeChecksum(fis1);
Checksum expChksum = ChecksumUtil.computeChecksum(fis2);
assertEquals(expChksum.getValue(), idxChksum.getValue());
fis1.close();
fis2.close();
}
}
@Test
public void testManifestOnVdbSave() throws Exception {
/* Copy the test data file as we don't want to overwrite it */
File tempDir = VdbPlugin.singleton().getStateLocation().toFile();
File booksVdbCopy = FileUtils.copy(VdbTestUtils.BOOKS_VDB_FILE, tempDir, true);
assertTrue(booksVdbCopy.exists());
/* Use the copy to test saving and checking out the manifest of the vdb */
MockFileBuilder booksVdbBuilder = new MockFileBuilder(booksVdbCopy);
booksVdbBuilder.addToModelWorkspace(modelWorkspaceMock);
when(booksVdbBuilder.getResourceFile().findMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE)).thenReturn(new IMarker[0]);
when(booksVdbBuilder.getResourceFile().createMarker(IMarker.PROBLEM)).thenReturn(mock(IMarker.class));
Vdb booksVdb = new XmiVdb(booksVdbBuilder.getResourceFile());
booksVdb.save();
JAXBContext jaxbContext = JAXBContext.newInstance(new Class<?>[] { VdbElement.class });
ZipFile archive = new ZipFile(booksVdbCopy);
Enumeration<? extends ZipEntry> iter = archive.entries();
while(iter.hasMoreElements()) {
ZipEntry zipEntry = iter.nextElement();
InputStream entryStream = archive.getInputStream(zipEntry);
if (! zipEntry.getName().equals(MANIFEST))
continue;
// Initialize using manifest
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
unmarshaller.setSchema(VdbUtil.getManifestSchema());
VdbElement manifest = (VdbElement) unmarshaller.unmarshal(entryStream);
assertEquals(2, manifest.getModels().size());
for (ModelElement element : manifest.getModels()) {
IPath path = Path.fromPortableString(element.getPath());
assertTrue(ModelUtil.isModelFile(path));
assertFalse(ModelUtil.isXsdFile(path));
/* Ensure the models are still under the project folder */
assertEquals(VdbTestUtils.TEST_2120, path.segment(path.segmentCount() - 2));
}
assertEquals(2, manifest.getEntries().size());
for (EntryElement element : manifest.getEntries()) {
IPath path = Path.fromPortableString(element.getPath());
assertTrue(ModelUtil.isXsdFile(path));
/* Ensure the xsd are still under the project folder */
assertEquals(VdbTestUtils.TEST_2120, path.segment(path.segmentCount() - 2));
for (PropertyElement prop : element.getProperties()) {
assertTrue(EntryElement.CHECKSUM.equals(prop.getName()) ||
EntryElement.INDEX_NAME.equals(prop.getName()));
}
}
entryStream.close();
}
archive.close();
}
/**
* Test for TEIIDES-2559
*
* @throws Exception
*/
@Test
public void testSaveOfUdfVdb() throws Exception {
/* Copy the test data file as we don't want to overwrite it */
File tempDir = VdbPlugin.singleton().getStateLocation().toFile();
File udfVdbCopy = FileUtils.copy(VdbTestUtils.UDF_VDB_FILE, tempDir, true);
assertTrue(udfVdbCopy.exists());
/* Use the copy to test saving and checking out the manifest of the vdb */
MockFileBuilder udfVdbBuilder = new MockFileBuilder(udfVdbCopy);
udfVdbBuilder.addToModelWorkspace(modelWorkspaceMock);
when(udfVdbBuilder.getResourceFile().findMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE)).thenReturn(new IMarker[0]);
when(udfVdbBuilder.getResourceFile().createMarker(IMarker.PROBLEM)).thenReturn(mock(IMarker.class));
Vdb udfVdb = new XmiVdb(udfVdbBuilder.getResourceFile());
udfVdb.save();
udfVdb.close();
boolean udfJarPresent = false;
boolean empSourceModelPresent = false;
int indexFilesPresent = 0;
boolean empViewModelPresent = false;
JAXBContext jaxbContext = JAXBContext.newInstance(new Class<?>[] { VdbElement.class });
ZipFile archive = new ZipFile(udfVdbCopy);
Enumeration<? extends ZipEntry> iter = archive.entries();
while(iter.hasMoreElements()) {
ZipEntry zipEntry = iter.nextElement();
InputStream entryStream = archive.getInputStream(zipEntry);
if (zipEntry.getName().equals(MANIFEST)) {
// Initialize using manifest
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
unmarshaller.setSchema(VdbUtil.getManifestSchema());
VdbElement manifest = (VdbElement) unmarshaller.unmarshal(entryStream);
assertEquals(2, manifest.getModels().size());
for (ModelElement element : manifest.getModels()) {
IPath path = Path.fromPortableString(element.getPath());
assertTrue(ModelUtil.isModelFile(path));
assertFalse(ModelUtil.isXsdFile(path));
/* Ensure the models are still under the project folder */
assertEquals(VdbTestUtils.TEST_UDF, path.segment(path.segmentCount() - 2));
}
assertEquals(1, manifest.getEntries().size());
for (EntryElement element : manifest.getEntries()) {
IPath path = Path.fromPortableString(element.getPath());
assertEquals(VdbFolders.UDF.getWriteFolder(), path.segment(0));
assertEquals("name_builder.jar", path.lastSegment());
}
} else {
//
// Assert that all the correct files are in the archive
//
// Should be 1 udf, 2 models and 2 index files
//
if (zipEntry.getName().equals("lib/name_builder.jar"))
udfJarPresent = true;
if (zipEntry.getName().equals("TestUDF/EMPLOYEEDATA_source.xmi"))
empSourceModelPresent = true;
if (zipEntry.getName().startsWith("runtime-inf") && zipEntry.getName().endsWith(".INDEX"))
indexFilesPresent++;
if (zipEntry.getName().equals("TestUDF/EMPLOYEE_VIEWS.xmi"))
empViewModelPresent = true;
}
entryStream.close();
}
archive.close();
assertTrue(udfJarPresent);
assertTrue(empSourceModelPresent);
assertEquals(2, indexFilesPresent);
assertTrue(empViewModelPresent);
//
// Create a new vdb based on the newly-saved version to check everything is intact
//
udfVdbBuilder = new MockFileBuilder(udfVdbCopy);
udfVdbBuilder.addToModelWorkspace(modelWorkspaceMock);
when(udfVdbBuilder.getResourceFile().findMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE)).thenReturn(new IMarker[0]);
when(udfVdbBuilder.getResourceFile().createMarker(IMarker.PROBLEM)).thenReturn(mock(IMarker.class));
udfVdb = new XmiVdb(udfVdbBuilder.getResourceFile());
Set<VdbFileEntry> udfJarEntries = udfVdb.getUdfJarEntries();
assertEquals(1, udfJarEntries.size());
VdbFileEntry udfEntry = udfJarEntries.iterator().next();
assertEquals("name_builder", udfEntry.getName());
assertEquals(File.separator + "lib" + File.separator + "name_builder.jar", udfEntry.getPath().toOSString());
assertEquals(FileEntryType.UDFJar, udfEntry.getFileType());
}
@Test
public void testVdbVersionCallback() throws Exception {
MockFileBuilder booksVdbBuilder = new MockFileBuilder(VdbTestUtils.BOOKS_VDB_FILE);
when(booksVdbBuilder.getResourceFile().exists()).thenReturn(true);
ValidationVersionCallback callback = new ValidationVersionCallback(booksVdbBuilder.getResourceFile());
VdbFileProcessor processor = new VdbFileProcessor(callback);
processor.process();
/* Original books vdb pre-dates validation version */
assertFalse(callback.hasException());
assertNull(callback.getValidationVersion());
booksVdbBuilder = new MockFileBuilder(VdbTestUtils.BOOKS_77_VDB_FILE);
when(booksVdbBuilder.getResourceFile().exists()).thenReturn(true);
callback = new ValidationVersionCallback(booksVdbBuilder.getResourceFile());
processor = new VdbFileProcessor(callback);
processor.process();
assertFalse(callback.hasException());
assertEquals(Version.TEIID_7_7.get(), callback.getValidationVersion());
booksVdbBuilder = new MockFileBuilder(VdbTestUtils.BOOKS_84_VDB_FILE);
when(booksVdbBuilder.getResourceFile().exists()).thenReturn(true);
callback = new ValidationVersionCallback(booksVdbBuilder.getResourceFile());
processor = new VdbFileProcessor(callback);
processor.process();
assertFalse(callback.hasException());
assertEquals(Version.TEIID_8_4.get(), callback.getValidationVersion());
}
@Test
public void testRemoveDataRole() {
DataRole role = new DataRole("TestDataRole");
XmiVdb vdb = new XmiVdb();
assertTrue(vdb.addDataRole(role));
assertTrue(vdb.getDataRoles().contains(role));
assertTrue(vdb.removeDataRole(role.getName()));
assertFalse(vdb.getDataRoles().contains(role));
assertTrue(vdb.getDataRoles().isEmpty());
}
}