/*
* 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.ddl.importer;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNull.notNullValue;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.util.List;
import java.util.Properties;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.teiid.core.designer.EclipseMock;
import org.teiid.core.designer.exception.EmptyArgumentException;
import org.teiid.core.designer.util.StringConstants;
import org.teiid.core.util.SmartTestDesignerSuite;
import org.teiid.designer.core.workspace.MockFileBuilder;
import org.teiid.designer.core.workspace.ModelResource;
import org.teiid.designer.core.workspace.ModelUtil;
import org.teiid.designer.core.workspace.ModelWorkspaceManager;
import org.teiid.designer.metamodels.core.ModelAnnotation;
import org.teiid.designer.metamodels.core.ModelType;
import org.teiid.designer.metamodels.relational.BaseTable;
import org.teiid.designer.metamodels.relational.Column;
public class DdlImporterTest {
private static final String EMPTY_XMI_CONTENTS = "<?xml version=\"1.0\" encoding=\"ASCII\"?>" + StringConstants.NEW_LINE
+ "<xmi:XMI xmi:version=\"2.0\" xmlns:xmi=\"http://www.omg.org/XMI\" "
+ "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
+ "xmlns:diagram=\"http://www.metamatrix.com/metamodels/Diagram\" "
+ "xmlns:mmcore=\"http://www.metamatrix.com/metamodels/Core\" "
+ "xmlns:relational=\"http://www.metamatrix.com/metamodels/Relational\">"
+ StringConstants.NEW_LINE
+ "<mmcore:ModelAnnotation xmi:uuid=\"mmuuid:0863dd9d-c34b-4291-9099-0b84910fa4e5\" "
+ "modelType=\"VIRTUAL\" "
+ "primaryMetamodelUri=\"http://www.metamatrix.com/metamodels/Relational\"/>"
+ StringConstants.NEW_LINE + "</xmi:XMI>";
private static final String TEIID_DIALECT = "TEIID"; //$NON-NLS-1$
private static final File TEST_DDL_FILE = SmartTestDesignerSuite.getTestDataFile(DdlImporterTest.class, "createTables.ddl");
private EclipseMock eclipseMock;
private DdlImporter importer;
private DdlImporter createImporter(IProject[] projects) {
return new DdlImporter(projects);
}
@Before
public void setUp() {
eclipseMock = new EclipseMock();
importer = createImporter(null);
}
@After
public void tearDown() throws Exception {
eclipseMock.dispose();
eclipseMock = null;
}
private MockFileBuilder createEmptyXmiFile() throws Exception, IOException {
final MockFileBuilder modelBuilder = new MockFileBuilder("blah", StringConstants.XMI);
FileWriter writer = null;
try {
writer = new FileWriter(modelBuilder.getRealFile());
writer.write(EMPTY_XMI_CONTENTS);
} finally {
if (writer != null)
writer.close();
}
assertTrue(ModelUtil.isModelFile(modelBuilder.getPath()));
return modelBuilder;
}
private ModelResource importDdl(final String ddl) throws Exception {
final NullProgressMonitor monitor = new NullProgressMonitor();
final MockFileBuilder modelBuilder = createEmptyXmiFile();
final IPath path = new Path(File.separator + modelBuilder.getProject().getName() + File.separator
+ modelBuilder.getName());
when(eclipseMock.workspaceRoot().findMember(path)).thenReturn(modelBuilder.getResourceFile());
when(eclipseMock.workspace().validateName(isA(String.class), anyInt())).thenReturn(Status.OK_STATUS);
final ModelWorkspaceManager workspaceManager = ModelWorkspaceManager.getModelWorkspaceManager();
final ModelResource modelResource = (ModelResource)workspaceManager.findModelWorkspaceItem(modelBuilder.getResourceFile(),
true);
assertNotNull(modelResource);
// create annotation
final ModelAnnotation annotation = modelResource.getModelAnnotation();
assertNotNull(annotation);
modelResource.save(monitor, false);
// import
final DdlImporter importer = new DdlImporter(new IProject[] {modelBuilder.getProject()});
importer.setSpecifiedParser(TEIID_DIALECT);
importer.setModelFolder(modelBuilder.getProject());
importer.setModelName(modelBuilder.getName());
importer.setModelType(ModelType.VIRTUAL_LITERAL);
importer.importDdl(ddl, monitor, 1, new Properties());
assertFalse(importer.noDdlImported());
assertNull(importer.getParseErrorMessage());
importer.save(monitor, 1);
assertTrue(importer.getImportStatus().isOK());
return modelResource;
}
@Test
public void shouldAcceptNewModel() {
when(eclipseMock.workspace().validateName(anyString(), eq(IResource.FILE))).thenReturn(Status.OK_STATUS);
final IFile model = mock(IFile.class);
when(eclipseMock.workspaceRoot().getFile((IPath)anyObject())).thenReturn(model);
importer.setModelName("model");
}
@Test( expected = IllegalArgumentException.class )
public void shouldFailIfDdlFileDoesNotExist() {
importer.setDdlFileName("doesNotExist");
}
@Test( expected = EmptyArgumentException.class )
public void shouldFailIfDdlFileNameIsEmpty() {
importer.setDdlFileName(" ");
}
@Test( expected = EmptyArgumentException.class )
public void shouldFailIfDdlFileNameIsNull() {
importer.setDdlFileName(null);
}
@Test( expected = IllegalArgumentException.class )
public void shouldFailIfModelFolderInNonModelProject() {
final IProject project = mock(IProject.class);
when(eclipseMock.workspaceRoot().findMember("project")).thenReturn(project);
final DdlImporter importer = createImporter(new IProject[] {project});
importer.setModelFolder("project/folder");
}
@Test( expected = IllegalArgumentException.class )
public void shouldFailIfModelFolderIsFile() {
final String folder = "project/file";
final IPath path = Path.fromPortableString(folder).makeAbsolute();
final IProject project = mock(IProject.class);
final IWorkspaceRoot root = eclipseMock.workspaceRoot();
final String projectName = path.segment(0);
when(root.findMember(projectName)).thenReturn(project);
when(project.getName()).thenReturn(projectName);
when(eclipseMock.workspace().validatePath(path.toString(), IResource.PROJECT | IResource.FOLDER)).thenReturn(Status.OK_STATUS);
final IFile file = mock(IFile.class);
when(root.findMember(path)).thenReturn(file);
final DdlImporter importer = createImporter(new IProject[] {project});
importer.setModelFolder(folder);
}
@Test( expected = EmptyArgumentException.class )
public void shouldFailIfModelFolderNameHasNoSegments() {
importer.setModelFolder("/");
}
@Test( expected = EmptyArgumentException.class )
public void shouldFailIfModelFolderNameIsEmpty() {
importer.setModelFolder(" ");
}
@Test( expected = EmptyArgumentException.class )
public void shouldFailIfModelFolderNameIsNull() {
importer.setModelFolder((String)null);
}
@Test( expected = EmptyArgumentException.class )
public void shouldFailIfModelNameIsEmpty() {
importer.setModelName(" ");
}
@Test( expected = EmptyArgumentException.class )
public void shouldFailIfModelNameIsNull() {
importer.setModelName(null);
}
@Test
public void shouldProvideDdlFile() {
importer.setDdlFileName(TEST_DDL_FILE.getAbsolutePath());
assertThat(importer.ddlFileName(), is(TEST_DDL_FILE.getAbsolutePath()));
}
@Test
public void shouldProvideModel() {
when(eclipseMock.workspace().validateName(anyString(), eq(IResource.FILE))).thenReturn(Status.OK_STATUS);
final IFile modelFile = mock(IFile.class);
final IPath modelPath = mock(IPath.class);
when(modelPath.removeFileExtension()).thenReturn(modelPath);
when(modelFile.getFullPath()).thenReturn(modelPath);
when(eclipseMock.workspaceRoot().getFile((IPath)anyObject())).thenReturn(modelFile);
final IFolder folder = mock(IFolder.class);
final IPath folderPath = mock(IPath.class);
when(folder.getFullPath()).thenReturn(folderPath);
when(folderPath.append(anyString())).thenReturn(folderPath);
importer.setModelFolder(folder);
importer.setModelName("model");
assertThat(importer.modelFile(), notNullValue());
}
@Test
public void shouldProvideModelFolder() {
when(eclipseMock.workspace().validatePath(anyString(), eq(IResource.PROJECT | IResource.FOLDER))).thenReturn(Status.OK_STATUS);
final IFolder folder = mock(IFolder.class);
when(eclipseMock.workspaceRoot().getFolder((IPath)anyObject())).thenReturn(folder);
importer.setModelFolder("project/folder");
assertThat(importer.modelFolder(), notNullValue());
final IContainer container = mock(IContainer.class);
importer.setModelFolder(container);
assertThat(importer.modelFolder(), is(container));
}
/**
* Verify fix for TEIIDDES-2558.
*/
@Test
public void shouldImportTableCardinalityGreaterThanMaxInt() throws Exception {
final File ddlFile = SmartTestDesignerSuite.getTestDataFile(DdlImporterTest.class, "fixed-postgres-vdb.xml");
final String ddl = new String(Files.readAllBytes(ddlFile.toPath()));
final ModelResource model = importDdl(ddl);
for (final Object obj : model.getAllRootEObjects()) {
if (obj instanceof BaseTable) {
final BaseTable table = (BaseTable)obj;
final String tableName = table.getName();
final int cardinality = table.getCardinality();
final String actual = convertIntToFloatString(cardinality);
String expected = "";
// take a few values from the DDL file
if ("lineitem".equals(tableName)) {
expected = "6000000000"; // > Integer.MAX_VALUE
} else if ("orders".equals(tableName)) {
expected = "1500000000";
} else if ("region".equals(tableName)) {
expected = "5";
} else {
continue;
}
assertThat(actual, is(expected));
}
}
}
/**
* Verify fix for TEIIDDES-1810.
*/
@Test
public void shouldImportColumnStatisticValuesGreaterThanMaxInt() throws Exception {
final File ddlFile = SmartTestDesignerSuite.getTestDataFile(DdlImporterTest.class, "largeColumnStatisticValues.xml");
final String ddl = new String(Files.readAllBytes(ddlFile.toPath()));
final ModelResource model = importDdl(ddl);
for (final Object obj : model.getAllRootEObjects()) {
if (obj instanceof BaseTable) {
final BaseTable table = (BaseTable)obj;
final String tableName = table.getName();
assertThat(tableName, is("largeColumnStatisticValues"));
final List<Column> columns = table.getColumns();
assertThat(columns.size(), is(2));
final Column col1 = columns.get(0);
int distinctValueCount = -1;
int nullValueCount = -1;
if ("col_a".equals(col1.getName())) {
distinctValueCount = col1.getDistinctValueCount();
nullValueCount = columns.get(1).getNullValueCount();
} else if ("col_b".equals(col1.getName())) {
nullValueCount = col1.getNullValueCount();
distinctValueCount = columns.get(1).getDistinctValueCount();
} else {
fail("Unexpected column name of " + col1.getName());
}
final String distinctValueCountAsString = convertIntToFloatString(distinctValueCount);
assertThat(distinctValueCountAsString, is("3500000000"));
final String nullValueCountAsString = convertIntToFloatString(nullValueCount);
assertThat(nullValueCountAsString, is("6000000000"));
}
}
}
private String convertIntToFloatString(final int value) {
// copied from FloatAsIntPropertyEditorFactory
if (value >= -1) {
return Integer.toString(value);
}
final float floatValue = Float.intBitsToFloat(value & 0x7fffffff);
return String.format("%.0f", floatValue);
}
}