/*
* Copyright 2013 Matt Sicker and Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package atg.tools.dynunit.adapter.gsa;
import atg.adapter.gsa.GSAId;
import atg.adapter.gsa.GSAItemDescriptor;
import atg.adapter.gsa.GSARepository;
import atg.beans.DynamicPropertyDescriptor;
import atg.core.util.StringUtils;
import atg.nucleus.Nucleus;
import atg.nucleus.servlet.NucleusServlet;
import atg.repository.MutableRepositoryItem;
import atg.repository.RepositoryException;
import atg.repository.RepositoryPropertyDescriptor;
import atg.service.idgen.IdGenerator;
import atg.service.idgen.IdGeneratorException;
import atg.tools.dynunit.test.util.DBUtils;
import junit.framework.TestCase;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.Nullable;
import java.beans.PropertyEditor;
import java.io.File;
import java.net.URL;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.Properties;
import java.util.Random;
// TODO: port to JUnit4
/**
* A basic GSA test which is expected to be extended than used directly.
* Has several utility methods.
*
* @author adwivedi
*/
public class GSATest
extends TestCase {
private final transient Random random = new Random();
private static final Logger logger = LogManager.getLogger();
private final HashMap<String, File> mConfigDir = new HashMap<String, File>();
/**
*
*/
public GSATest() {
super();
// TODO Auto-generated constructor stub
}
/**
* Constructor for GSATest.
*
* @param arg0
*/
public GSATest(String arg0) {
super(arg0);
}
public File getConfigpath() {
return getConfigpath(null);
}
/**
* Returns the configpath for tests
*
* @return
*/
File getConfigpath(@Nullable String pConfigDirectory) {
if ( mConfigDir.get(pConfigDirectory) == null ) {
String configdirname = "config";
String packageName = StringUtils.replace(
this.getClass().getPackage().getName(), '.', "/"
);
if ( pConfigDirectory != null ) {
configdirname = pConfigDirectory;
}
String configFolder = packageName + "/data/" + configdirname;
URL dataURL = this.getClass().getClassLoader().getResource(configFolder);
// Mkdir
if ( dataURL == null ) {
URL root = this.getClass().getClassLoader().getResource(packageName);
File f = null;
if ( root != null ) {
f = new File(root.getFile());
}
File f2 = new File(f, "/data/" + configdirname);
f2.mkdirs();
dataURL = this.getClass().getClassLoader().getResource(configFolder);
}
if ( dataURL != null ) {
mConfigDir.put(pConfigDirectory, new File(dataURL.getFile()));
}
}
System.setProperty(
"atg.configpath", mConfigDir.get(pConfigDirectory).getAbsolutePath()
);
return mConfigDir.get(pConfigDirectory);
}
/**
* Create a repository in the given configpath using the given repository definitions (Absolute
* paths)
* connecting to the db whose properties are specified in pDBProperties @see DBUtils
* Method pMethodName is invoked with the GSARepository passed to it as a parameter.
*
* @param pConfigPathWhereToCreateTheRepository
*
* @param definitionFiles
* @param pDBProperties
* @param pMethodName
*
* @throws Exception
*/
void setUpAndTest(File pConfigPathWhereToCreateTheRepository,
String[] definitionFiles,
Properties pDBProperties,
String pMethodName)
throws Exception {
String repositoryComponentPath = "/" + getName() + "Repository";
GSATestUtils.getGSATestUtils().initializeMinimalConfigpath(
pConfigPathWhereToCreateTheRepository,
repositoryComponentPath,
definitionFiles,
pDBProperties,
null,
null,
null,
true
);
Nucleus n = startNucleus(pConfigPathWhereToCreateTheRepository);
GSARepository r = (GSARepository) n.resolveName(repositoryComponentPath);
try {
getClass().getMethod(pMethodName, new Class[] { GSARepository.class })
.invoke(this, r);
} catch ( NoSuchMethodError e ) {
throw new AssertionError(
"Please declare a method with name "
+ pMethodName
+ " in your class. It must take an atg.adapter.gsa.GSARepository as the only parameter."
);
} finally {
// if it were null a NPE would have occurred at the earlier dereference
//if(n != null)
n.stopService();
}
}
/**
* Create a file using reasonable defaults.
* Your definition file should exist in the same package as the test and should be
* names <test_name>Repository.xml. Configpath is assumed to be what is returned
*
* @param pMethodName
*
* @throws Exception
*/
protected void setUpAndTest(String pMethodName)
throws Exception {
File configPathWhereToCreateTheRepository = getConfigpath(null);
String packageName = StringUtils.replace(
this.getClass().getPackage().getName(), '.', "/"
);
String fileName = packageName + "/" + getName() + "Repository.xml";
URL defaultDefinitionFile = getClass().getResource("/" + fileName);
if ( defaultDefinitionFile == null ) {
throw new AssertionError(
"DUDE, I need a file called : " + fileName + " to start a GSA repository from. "
);
}
String[] definitionFiles = new String[] { fileName };
Properties DBProperties = DBUtils.getHSQLDBInMemoryDBConnection();
setUpAndTest(
configPathWhereToCreateTheRepository, definitionFiles, DBProperties, pMethodName
);
}
/**
* Starts Nucleus using the given config directory
*
* @param configpath
*
* @return
*/
public static Nucleus startNucleus(File configpath) {
return startNucleus(configpath.getAbsolutePath());
}
/**
* Starts Nucleus given an array of configpath entries
*
* @param configpathStr
*
* @return
*/
public static Nucleus startNucleus(String configpathStr) {
System.setProperty("atg.dynamo.license.read", "true");
System.setProperty("atg.license.read", "true");
NucleusServlet.addNamingFactoriesAndProtocolHandlers();
return Nucleus.startNucleus(new String[] { configpathStr });
}
/**
* @param props
*
* @return
* @throws Exception
* @throws SQLException
*/
protected DBUtils initDB(Properties props)
throws Exception {
return new DBUtils(
props.getProperty("URL"),
props.getProperty("driver"),
props.getProperty("user"),
props.getProperty("password")
);
}
/**
* A Dummy test so smokestack won't report this
* class as a failure.
* It expects that all *Test.class files have
* at least one test.
*/
public final void testDummy() {
}
/**
* @param pGSARepository
* @param descName
*
* @return
* @throws RepositoryException
*/
protected MutableRepositoryItem createDummyItem(GSARepository pGSARepository,
String descName,
String pID)
throws RepositoryException {
GSAItemDescriptor descriptor = (GSAItemDescriptor) pGSARepository.getItemDescriptor(descName);
MutableRepositoryItem item = null;
boolean compoundPrimaryKey = descriptor.getPrimaryTable().getIdColumnCount() > 1;
if ( pID == null || pID.trim().length() == 0 ) {
if ( compoundPrimaryKey ) {
item = pGSARepository.createItem(
getNewCompoundId(pGSARepository, descriptor), descName
);
} else {
item = pGSARepository.createItem(descName);
}
} else {
item = pGSARepository.createItem(pID, descName);
}
RepositoryPropertyDescriptor[] propDescriptors = (RepositoryPropertyDescriptor[]) descriptor
.getPropertyDescriptors();
for ( RepositoryPropertyDescriptor propertyDescriptor : propDescriptors ) {
if ( propertyDescriptor.isWritable()
&& !propertyDescriptor.isIdProperty()
&& propertyDescriptor.isRequired() ) {
if (!propertyDescriptor.isCollectionOrMap()) {
Object dummyPropertyValue = generateDummyValue(propertyDescriptor);
if ( dummyPropertyValue != null ) {
item.setPropertyValue(
propertyDescriptor.getName(), dummyPropertyValue
);
}
}
}
}
return item;
}
/**
* Get a id suitable for creating items of this type. We use out
* <code>Repository</code>'s <code>IdGenerator</code>.
*
* @return a new id, which is unique across all items in this
* repository with this item descriptor.
* @throws RepositoryException if there is trouble creating the id
*/
GSAId getNewCompoundId(GSARepository r, GSAItemDescriptor desc)
throws RepositoryException {
// make sure we have a repository
if ( r == null ) {
return null;
}
// get the generator to use
IdGenerator gen = r.getIdGenerator();
if ( gen == null ) {
return null;
}
Class<?>[] types = desc.getIdTypes();
String[] idSpaceNames = desc.getIdSpaceNames();
Object[] newId = new Object[types.length];
if ( idSpaceNames.length != types.length ) {
throw new RepositoryException("No ID SPACES ! " + desc.getItemDescriptorName());
}
// generate an id in our id space and return it
try {
for ( int i = 0; i < types.length; i++ ) {
if ( types[i] == String.class ) {
if ( i > 0 ) {
newId[i] = "dummyIdPart";
} else {
newId[i] = gen.generateStringId(idSpaceNames[i]);
}
} else {
long val = gen.generateLongId(idSpaceNames[i]);
if ( types[i] == Long.class ) {
newId[i] = val;
} else if ( types[i] == Float.class ) {
newId[i] = (float) val;
} else if ( types[i] == Double.class ) {
newId[i] = (double) val;
} else if ( types[i] == java.sql.Timestamp.class ) {
newId[i] = new java.sql.Timestamp(val);
} else if ( types[i] == java.util.Date.class ) {
newId[i] = new java.util.Date(val);
} else {
newId[i] = (int) val;
}
}
}
} catch ( IdGeneratorException ie ) {
throw new RepositoryException(ie);
}
return desc.generateGSAId(newId);
}
@SuppressWarnings("unchecked")
Object generateDummyValue(RepositoryPropertyDescriptor propertyDescriptor) {
if ( getEnumeratedValues(propertyDescriptor) != null ) {
return null;// ignore enums for now.
}
if ( propertyDescriptor.getPropertyType().isAssignableFrom(
java.lang.String.class
) ) {
return generateString();
} else if ( propertyDescriptor.getPropertyType().isAssignableFrom(
java.lang.Integer.class
) ) {
return generateInteger();
} else if ( propertyDescriptor.getPropertyType().isAssignableFrom(
java.lang.Boolean.class
) ) {
return generateBoolean();
} else if ( propertyDescriptor.getPropertyType().isAssignableFrom(
java.lang.Byte.class
) ) {
return generateByte();
} else if ( propertyDescriptor.getPropertyType().isAssignableFrom(
java.lang.Short.class
) ) {
return generateShort();
} else if ( propertyDescriptor.getPropertyType().isAssignableFrom(
java.lang.Long.class
) ) {
return generateLong();
} else if ( propertyDescriptor.getPropertyType().isAssignableFrom(
java.lang.Float.class
) ) {
return generateFloat();
} else if ( propertyDescriptor.getPropertyType().isAssignableFrom(
java.lang.Double.class
) ) {
return generateDouble();
} else if ( propertyDescriptor.getPropertyType().isAssignableFrom(
(new byte[0]).getClass()
) )//BINARY
{
return null;
// return generateBinary();
} else if ( propertyDescriptor.getPropertyType().isAssignableFrom(
java.sql.Timestamp.class
) ) {
return generateTimestamp();
} else if ( propertyDescriptor.getPropertyType().isAssignableFrom(
java.sql.Date.class
) ) {
return generateDate();
}
return null;
}
/**
* Returns the set of enumerated values, or null if there are none
*/
String[] getEnumeratedValues(DynamicPropertyDescriptor pDescriptor) {
if ( pDescriptor == null ) {
return null;
}
PropertyEditor pe = getPropertyEditor(pDescriptor);
String[] ret = (pe == null) ? null : pe.getTags();
// make sure it's not just a boolean value
Class<?> type = pDescriptor.getPropertyType();
if ( (type == Boolean.class || type == Boolean.TYPE)
&& ret != null
&& ret.length == 2
&& (("true".equals(ret[0]) && "false".equals(ret[1])) || ("false".equals(ret[0])
&& "true".equals(ret[1]))) ) {
return null;
} else {
return ret;
}
}
/**
* Returns an instance of the property editor, null if there is no
* property editor
*/
PropertyEditor getPropertyEditor(DynamicPropertyDescriptor propertyDescriptor) {
if ( propertyDescriptor == null ) {
return null;
}
Class<?> propertyEditorClass = propertyDescriptor.getPropertyEditorClass();
if ( propertyEditorClass == null ) {
return propertyDescriptor.getUIPropertyEditor();
} else {
Object propertyEditor = null;
try {
propertyEditor = propertyEditorClass.newInstance();
} catch ( InstantiationException e ) {
logger.catching(Level.ERROR, e);
} catch ( IllegalAccessException e ) {
logger.catching(Level.ERROR, e);
}
if ( propertyEditor instanceof PropertyEditor ) {
return (PropertyEditor) propertyEditor;
} else {
return null;
}
}
}
/**
* @return
*/
private Object generateDate() {
return new Date(System.currentTimeMillis());
}
/**
* @return
*/
private Object generateTimestamp() {
return new Timestamp(System.currentTimeMillis());
}
// /**
// * @return
// */
// private Object generateBinary() {
// byte[] bytes = new byte[100];
// Random random = new Random();
// random.nextBytes(bytes);
// return bytes;
// }
/**
* @return
*/
private Object generateDouble() {
return random.nextDouble();
}
/**
* @return
*/
private Object generateInteger() {
return random.nextInt(32768);
}
/**
* @return
*/
private Object generateFloat() {
return random.nextFloat();
}
/**
* @return
*/
private Object generateLong() {
return (long) random.nextInt(32278);
}
/**
* @return
*/
private Object generateShort() {
return (short) (random.nextInt(100));
}
/**
* @return
*/
private Object generateByte() {
byte[] bytes = new byte[1];
random.nextBytes(bytes);
return bytes[0];
}
/**
* @return
*/
private Object generateBoolean() {
return random.nextBoolean();
}
/**
* @return
*/
private Object generateString() {
return "DUMMY STRING " + generateInteger();
}
}