Package com.force.sdk.jpa.schema

Source Code of com.force.sdk.jpa.schema.SchemaTest$PrecisionScale

/**
* Copyright (c) 2011, salesforce.com, inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided
* that the following conditions are met:
*
*    Redistributions of source code must retain the above copyright notice, this list of conditions and the
*    following disclaimer.
*
*    Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
*    the following disclaimer in the documentation and/or other materials provided with the distribution.
*
*    Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or
*    promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

package com.force.sdk.jpa.schema;

import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Pattern;

import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.persistence.PersistenceException;
import javax.persistence.metamodel.Attribute;

import org.apache.log4j.Appender;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.spi.LoggingEvent;
import org.datanucleus.exceptions.NucleusException;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import com.force.sdk.connector.ForceConnectorConfig;
import com.force.sdk.connector.ForceServiceConnector;
import com.force.sdk.jpa.schema.entities.ExistingCustomObject;
import com.force.sdk.jpa.schema.entities.StandardFieldLinkingEntity;
import com.force.sdk.qa.util.TestContext;
import com.sforce.soap.partner.DescribeSObjectResult;
import com.sforce.soap.partner.PartnerConnection;
import com.sforce.soap.partner.fault.InvalidSObjectFault;
import com.sforce.ws.ConnectionException;

/**
*
* Tests related to malformed schemas and the exceptions that the javasdk throws. This test uses multiple
* persistence unit definitions each containing one faulty schema element and asserts the exception at
* schema load time.
*
* @author Dirk Hain
*/
public class SchemaTest extends SchemaBaseTest {

    @DataProvider
    public Object[][] schemaDataProvider() throws NumberFormatException, MalformedURLException {
        Object [][] schemaTestVals = new Object[][]{
                {"testMappedSuperclassWithOverride",
                    "@AttributeOverride or @AssociationOverride is not supported by Force.com datastore."},
                {"testUniqueConstraint", "@UniqueConstraint is not supported by Force.com datastore"},
                {"testLob", "@Clob field type is not supported"},
                {"testJoinTable", "@JoinTable is not supported."},
                {"testNonCustomizableStandardObjectWithCustomField", "Cannot add custom fields to entity: CaseComment "},
                {"testNonStringPrimaryKey", "ID field type should be String"},
                {"testEmbeddableId", "ID field type should be String"},
                {"testCompositePrimaryKey", "Only single string column primary keys supported as ID by Force.com datastore"},
                {"testColumnWithTable", "Table cannot be specified at a column level"},
                {"testNegativePrimaryKey_TABLE",
                    "@Id column requires value generation @GeneratedValue(strategy = GenerationType.IDENTITY)"},
                {"testNegativePrimaryKey_AUTO",
                    "@Id column requires value generation @GeneratedValue(strategy = GenerationType.IDENTITY)"},
                {"testNegativePrimaryKey_SEQUENCE",
                    "@Id column requires value generation @GeneratedValue(strategy = GenerationType.IDENTITY)"},
                {"testTableGenerator",
                    "@Id column requires value generation @GeneratedValue(strategy = GenerationType.IDENTITY). "
                        + "Offending entity: com.force.sdk.jpa.schema.entities.TableGeneratorTest"},
                {"testSequenceGenerator",
                    "@Id column requires value generation @GeneratedValue(strategy = GenerationType.IDENTITY). "
                        + "Offending entity: com.force.sdk.jpa.schema.entities.SequenceGeneratorTest"},
                {"testNegativeInheritance_JOINED", "Only SINGLE_TABLE inheritance strategy supported by Force.com datastore"},
                {"testNegativeInheritance_TABLE_PER_CLASS",
                    "Only SINGLE_TABLE inheritance strategy supported by Force.com datastore"},
                {"testNegativeInheritance_JoinColumnOnSubtype", "@PrimaryKeyJoinColumn is not supported by Force.com datastore"},
                {"testSecondaryTable", "Secondary tables are not supported by Force.com datastore"},
                {"testEmbeddable", "Embedded objects cannot have table specification"},
                {"testManyToMany",
                    "@ManyToMany relationship is not supported. Please use a junction object with two @ManyToOne relationships"},
                {"testOneToMany",
                    "@OneToMany relationship requires the 'mappedBy' attribute. "
                        + "Please add a foreign key field on child object and use that field name for mappedBy attribute"},
                {"testNonStrictPicklistNonString",
                    "Non-strict picklist can be of type String or String[] only. Offending field: "},
                {"testNonStrictPicklistNonStringMP",
                    "Non-strict picklist can be of type String or String[] only. Offending field: "},
                {"testNonStrictPicklistValue",
                    "Non-strict picklist requires @PicklistValue annotation. Offending field: "},
                {"testNonStrictPicklistValueMP", "Non-strict picklist requires @PicklistValue annotation. Offending field: "},
                {"testNonStrictPicklistOrdinal", "Non-strict picklist does not support EnumType.ORDINAL. Offending field: "},
                {"testNonStrictPicklistOrdinalMP", "Non-strict picklist does not support EnumType.ORDINAL. Offending field: "},
                {"testCustomObjectWithPrefixDifferentFromOrgNamespace",
                    "Cannot create a new component with the namespace: NotANamespace."
                        + "  Only components in the same namespace as the organization can be created through the API"},
                {"testNewCustomObjectWithInvalidTableName", "Could not parse table: Two__Underscores__Twice__c"}
        };
        return schemaTestVals;
    }
 
   
    @Test(dataProvider = "schemaDataProvider")
    /**
     * Negative tests to assert proper exceptions during schema creation.
     * This set of tests is related to all schema exceptions that the javasdk throws
     * if a developer has provided an invalid schema.
     * @hierarchy javasdk
     * @userStory xyz
     * @expectedResults PersistenceException is thrown.
     */
    public <E extends PersistenceException> void testSchemaError(String persistenceUnitName, String exceptionMessage)
    throws Exception {
        Logger logger = Logger.getLogger("DataNucleus.MetaData");
        // We will run a lot of negative tests that DN will log. We want to avoid that
        Level oldLevel = logger.getLevel();
        logger.setLevel(Level.OFF);
        try {
            emfac = Persistence.createEntityManagerFactory(persistenceUnitName, dynamicOrgConfig);
            Assert.fail("Persistence unit " + persistenceUnitName + " contains an unsupported feature and should have"
                    + " thrown an exception.");
        } catch (PersistenceException e) {
            /**
             * This is really sucky, if we do org creation then as a side effect we add this property
             * "javax.persistence.provider" to initialization. This causes DataNucleus provider to try
             * to initialize these test persistence units too. As a result we hit the same error twice,
             * one for our provider and once for DN. Now when we have two exceptions in initialization
             * the error is reported to us in a flattened single level PersistenceException.
             * On the other hand when we do not do org creation we only get one exception which is not flattened.
             * In that cae we have to look at the NucleusUserException.
             * This is the code path that a typical misconfigured system will hit.
             */
            if (e.getCause() == null) {
                Assert.assertTrue(e.getMessage().contains(exceptionMessage), "Exception message was wrong: " + e.getMessage());
            } else {
                NucleusException cause = (NucleusException) e.getCause();
                if (cause.getNestedExceptions() == null) {
                    Assert.assertTrue(cause.getMessage().contains(exceptionMessage),
                            "Exception message was wrong: " + e.getMessage());
                } else {
                    Assert.assertTrue(cause.getNestedExceptions()[0].getMessage().contains(exceptionMessage),
                            "Exception message was wrong: " + e.getMessage());
                }
            }
        } finally {
            logger.setLevel(oldLevel);
        }
    }
   
   
    @Test
    /**
     * Verify that standard fields are linked to the JPA entity.
     * Tests that standard fields are linked to the entity upon schema creation. The {@link StandardFieldLinkingEntity}
     * defines standard fields explicitly and this tests makes sure that the standard fields are not recreated as
     * custom fields on the type during schema creation.
     * @hierarchy javasdk
     * @userStory xyz
     * @expectedResults StandardFieldLinkEntity should only have standard fields.
     */
    public void testLinkStandardFields() {
        emfac = Persistence.createEntityManagerFactory("testStandardFieldLinking", dynamicOrgConfig);
        em = emfac.createEntityManager();
        EntityTransaction tx = em.getTransaction();
        StandardFieldLinkingEntity entity = new StandardFieldLinkingEntity();
       
        try {
            tx.begin();
            entity.setName(StandardFieldLinkingEntity.class.getSimpleName());
            em.persist(entity);
            Assert.assertTrue(em.contains(entity), "The entity was not stored to the database.");
            tx.commit();
            StandardFieldLinkingEntity retrieve = em.find(StandardFieldLinkingEntity.class, entity.getId());
            Assert.assertEquals(retrieve.getName(), StandardFieldLinkingEntity.class.getSimpleName(),
                    "Entity was not retrieved properly.");
            Set<Attribute<? super StandardFieldLinkingEntity, ?>> attributes =
                em.getMetamodel().entity(StandardFieldLinkingEntity.class).getAttributes();
            Set<Field> s = removeJDOFields(StandardFieldLinkingEntity.class);
            Assert.assertEquals(attributes.size(), s.size(), "There was an unexpected number of attributes.");
            Iterator<Attribute<? super StandardFieldLinkingEntity, ?>> iter = attributes.iterator();
            while (iter.hasNext()) {
                Attribute<? super StandardFieldLinkingEntity, ?> attrib = iter.next();
                Assert.assertTrue(typeDefinesField(StandardFieldLinkingEntity.class, attrib.getName()), "Field ");
            }
        } catch (PersistenceException pex) {
            Assert.fail(pex.getMessage());
        }
    }
   
    @Test
    public void testExtendEntityClassesStandardFieldsOnly() throws Exception {
        emfac = Persistence.createEntityManagerFactory("testExtendEntityClassesStandardFieldsOnly", dynamicOrgConfig);
        em = emfac.createEntityManager();
        // check that custom object Vehicle__c is created correctly
        verifyFieldsOnSObject("Vehicle__c",
                new String[] { "CreatedById", "CreatedDate", "Id", "IsDeleted", "LastModifiedById""LastModifiedDate",
                                "Name", "OwnerId", "SystemModstamp"});
        // TODO: add verification for the child entities Car and AudiA8
    }
   
    @Test
    public void testExtendEntityClassesStandardWithCustomFields() throws Exception {
        emfac = Persistence.createEntityManagerFactory("testExtendEntityClassesStandardWithCustomFields", dynamicOrgConfig);
        em = emfac.createEntityManager();
        // check that custom object Animal__c is created correctly
        verifyFieldsOnSObject("Animal__c",
                new String[] { "CreatedById", "CreatedDate", "Id", "IsDeleted", "LastModifiedById", "LastModifiedDate",
                                "Name", "OwnerId", "SystemModstamp", "age__c"});
        // TODO: add verification for the child entities Bear and Mammal
    }
   
    @Test
    public void testExtendEntityClassesWithOneToManyRelationship() throws Exception {
        emfac = Persistence.createEntityManagerFactory("testExtendEntityClassesWithOneToManyRelationship", dynamicOrgConfig);
        em = emfac.createEntityManager();
        // check that custom object AbstractParentEntity__c is created correctly
        verifyFieldsOnSObject("AbstractParentEntity__c",
                new String[] { "CreatedById", "CreatedDate", "Id", "IsDeleted", "LastModifiedById""LastModifiedDate",
                                "Name""OwnerId", "SystemModstamp"});
        // check that custom object ChildWithAbstractParentEntity__c is created correctly
        verifyFieldsOnSObject("ChildWithAbstractParentEntity__c",
                new String[] { "CreatedById", "CreatedDate", "Id", "IsDeleted", "LastModifiedById""LastModifiedDate",
                                "Name""OwnerId", "SystemModstamp", "parent__c"});
        // TODO: add verification for ConcreteParentEntity__c
    }
   
    @Test
    /**
     * Startup with autoCreateSchema=false.
     * Test runs with autoCreateSchema = false and verifies appropriate error logs for missing tables and fields.
     * @hierarchy javasdk
     * @userStory xyz
     * @expectedResults Correct logs are received by Appender.
     */
    public void testAutoCreateSchemaFalse() {
        Persistence.createEntityManagerFactory("setupExistingCustomObject").createEntityManager();

        Logger logger = Logger.getLogger("com.force.sdk.jpa");
        Level oldLevel = logger.getLevel();
        logger.setLevel(Level.WARN);
        final AtomicBoolean receivedTableLog = new AtomicBoolean(false);
        final AtomicBoolean receivedFieldLog = new AtomicBoolean(false);
        Appender appender = new AppenderSkeleton() {
           
            private Pattern missingTablePat =
                Pattern.compile("Table does not exist in force.com and datanucleus.autoCreateTables is false,"
                                    + " table: [a-zA-Z0-9_$]*SimpleValidEntity__c");
            private Pattern missingFieldsPat =
                Pattern.compile("Field does not exist in force.com table and datanucleus.autoCreateColumns is false,"
                                    + " entity: ExistingCustomObjectExtension1 table: [a-zA-Z0-9_$]*"
                                    + "ExistingCustomObject__c fields: \\[newCustomField1\\]");
           
            @Override
            public boolean requiresLayout() {
                return false;
            }
           
            @Override
            public void close() {
            }
           
            @Override
            protected void append(LoggingEvent event) {
                if (event != null) {
                    if (missingTablePat.matcher(event.getRenderedMessage()).find()) {
                        receivedTableLog.set(true);
                    } else if (missingFieldsPat.matcher(event.getRenderedMessage()).find()) {
                        receivedFieldLog.set(true);
                    }
                }
            }
        };
        logger.addAppender(appender);
       
        try {
            emfac = Persistence.createEntityManagerFactory("testAutoCreateSchemaFalse", dynamicOrgConfig);
            em = emfac.createEntityManager();
            ExistingCustomObject ent = new ExistingCustomObject();
            ent.setExistingCustomField("some value");
            EntityTransaction tx = em.getTransaction();
            tx.begin();
            em.persist(ent);
            tx.commit();
           
            ExistingCustomObject result = em.find(ExistingCustomObject.class, ent.getId());
            Assert.assertEquals(result.getExistingCustomField(), "some value");
           
            Assert.assertTrue(receivedTableLog.get(), "Did not receive log messages for missing tables");
            Assert.assertTrue(receivedFieldLog.get(), "Did not receive log messages for missing fields");
        } finally {
            logger.setLevel(oldLevel);
            logger.removeAppender(appender);
        }
    }
   
    @Test
    /**
     * Test for entity hierarchy of one level (i.e. JPAClass extends OtherJPAClass).
     * Verifies that JPA entity hierarchies are mapped correctly to salesforce objects by the javasdk.
     * @hierarchy javasdk
     * @userStory xyz
     * @expectedResults Correct fields should be present in testExtendOneLevel object.
     */
    public void testExtendOneLevel() throws Exception {
        emfac = Persistence.createEntityManagerFactory("testExtendOneLevel", dynamicOrgConfig);
        em = emfac.createEntityManager();
       
        verifyFieldsOnSObject("OneLevelParent__c",
            new String[] {"CreatedById" , "CreatedDate", "Id", "IsDeleted", "LastModifiedById",
                "LastModifiedDate", "Name", "OwnerId", "SystemModstamp", "childOnly__c" }
                );
    }
   
    @Test
    public void testMappedSuperclass() throws Exception {
        emfac = Persistence.createEntityManagerFactory("testMappedSuperclass", dynamicOrgConfig);
        em = emfac.createEntityManager();
       
        // The sub-class should have fields from the mapped super class as well
        verifyFieldsOnSObject("MappedSubclassEntity__c",
                new String[] {"CreatedById", "CreatedDate", "Id", "IsDeleted", "LastModifiedById",
                "LastModifiedDate", "Name", "OwnerId", "SystemModstamp", "someSubtypeValue__c", "someSuperTypeValue__c"});
    }
   
    @Test
    public void testCreateCustomOwnerObject() throws Exception {
        Persistence.createEntityManagerFactory("testCreateCustomOwnerObject", dynamicOrgConfig).createEntityManager();
       
        try {
            service.describeSObject(getObjectApiPrefix() + "Owner__c");
        } catch (InvalidSObjectFault e) {
            Assert.fail("Custom Owner object was not created.", e);
        }
    }
   
    @Test
    /**
     * Numerical field precision.
     * Verifies that the precision of numerical fields generated in the schema is correct.
     * @hierarchy javasdk
     * @userStory xyz
     * @expectedResults Correct fields should be present in testNumericTypePrecision object.
     */
    public void testNumericalFieldPrecision() throws Exception {
        emfac = Persistence.createEntityManagerFactory("testNumericTypePrecision", dynamicOrgConfig);
        em = emfac.createEntityManager();
        verifyFieldsOnSObject("AllNumericTypes__c",
            new String[] {"CreatedById" , "CreatedDate", "Id", "IsDeleted", "LastModifiedById",
                "LastModifiedDate", "Name", "OwnerId", "SystemModstamp", "integerObject__c", "integerPrimitive__c",
                "shortObject__c", "shortPrimitive__c", "doubleObject__c", "doublePrimitive__c",
                "longObject__c", "longPrimitive__c", "floatObject__c", "floatPrimitive__c", "bigInteger__c", "bigDecimal__c" }
                );
       
        String prefix = getObjectApiPrefix();
       
        Map<String, PrecisionScale> expectedFieldMetadata = new HashMap<String, PrecisionScale>();
        expectedFieldMetadata.put(prefix + "integerObject__c", new PrecisionScale(11, 0));
        expectedFieldMetadata.put(prefix + "integerPrimitive__c", new PrecisionScale(11, 0));
        expectedFieldMetadata.put(prefix + "shortObject__c", new PrecisionScale(6, 0));
        expectedFieldMetadata.put(prefix + "shortPrimitive__c", new PrecisionScale(6, 0));
        expectedFieldMetadata.put(prefix + "doubleObject__c", new PrecisionScale(16, 2));
        expectedFieldMetadata.put(prefix + "doublePrimitive__c", new PrecisionScale(16, 2));
        expectedFieldMetadata.put(prefix + "longObject__c", new PrecisionScale(18, 0));
        expectedFieldMetadata.put(prefix + "longPrimitive__c", new PrecisionScale(18, 0));
        expectedFieldMetadata.put(prefix + "floatObject__c", new PrecisionScale(16, 2));
        expectedFieldMetadata.put(prefix + "floatPrimitive__c", new PrecisionScale(16, 2));
        expectedFieldMetadata.put(prefix + "bigInteger__c", new PrecisionScale(18, 0));
        expectedFieldMetadata.put(prefix + "bigDecimal__c", new PrecisionScale(16, 2));

        verifyFieldPrecisions(prefix + "AllNumericTypes__c", expectedFieldMetadata);
           
    }
   
    /**
     * Class to encapsulate precision and scale for numeric fields.
     *
     * @author Dirk Hain
     */
    private static class PrecisionScale {
        public int precision;
        public int scale;
       
        public PrecisionScale(int precision, int scale) {
            this.precision = precision;
            this.scale = scale;
        }
    }
   
    /**
     * Verifies that fields are correct in the underlying salesforce custom object.
     */
    private void verifyFieldsOnSObject(String sObject, String[] expectedFieldNames) throws Exception {
        PartnerConnection conn = getPartnerConnection();
        String ns = getNamespaceFromCtx();
        if (ns != null && ns != "") {
            sObject = ns + NAME_SEPARATOR + sObject;
        }
        DescribeSObjectResult describeSObjectResult = conn.describeSObject(sObject);
        com.sforce.soap.partner.Field[] fields = describeSObjectResult.getFields();
        Assert.assertEquals(fields.length, expectedFieldNames.length, "Unexpected number of fields on object " + sObject);
        ArrayList<String> fieldNames = new ArrayList<String>();
        for (com.sforce.soap.partner.Field field : fields) {
            if (field.isCustom() && ns != null && ns != "") {
                String fn = field.getName();
                fieldNames.add(fn.substring(ns.length() + NAME_SEPARATOR.length()));
            } else {
                fieldNames.add(field.getName());
            }
        }
        Collections.sort(fieldNames);
        Arrays.sort(expectedFieldNames);
       
        for (int i = 0; i < fieldNames.size(); i++) {
            Assert.assertEquals(fieldNames.get(i), expectedFieldNames[i], "Unexpected field name");
        }
    }
   
    /**
     * Verifies that field precisions and decimal place counts are correct
     * in the underlying salesforce custom object.
     */
    private void verifyFieldPrecisions(String sObject,
            Map<String, PrecisionScale> expectedFieldMetadata) throws Exception {
        PartnerConnection conn = getPartnerConnection();
        DescribeSObjectResult describeSObjectResult = conn.describeSObject(sObject);
        com.sforce.soap.partner.Field[] fields = describeSObjectResult.getFields();

        for (int i = 0; i < fields.length; i++) {
            if (expectedFieldMetadata.containsKey(fields[i].getName())) {
                Assert.assertEquals(
                        fields[i].getPrecision(),
                        expectedFieldMetadata.get(fields[i].getName()).precision,
                        "Unexpected precisions on field: " + fields[i].getName());
                Assert.assertEquals(
                        fields[i].getScale(),
                        expectedFieldMetadata.get(fields[i].getName()).scale,
                        "Unexpected precisions on field: " + fields[i].getName());
            }
        }
    }
   
    private PartnerConnection getPartnerConnection() throws ConnectionException {
        ForceConnectorConfig config = new ForceConnectorConfig();
        config.setAuthEndpoint(TestContext.get().getUserInfo().getServerEndpoint());
        config.setUsername(TestContext.get().getUserInfo().getUserName());
        config.setPassword(TestContext.get().getUserInfo().getPassword());
        return new ForceServiceConnector(config).getConnection();
    }
   
}
TOP

Related Classes of com.force.sdk.jpa.schema.SchemaTest$PrecisionScale

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.