de.hybris.platform.cronjob.jalo.TriggerableJobTest.java Source code

Java tutorial

Introduction

Here is the source code for de.hybris.platform.cronjob.jalo.TriggerableJobTest.java

Source

/*
 * [y] hybris Platform
 *
 * Copyright (c) 2000-2013 hybris AG
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of hybris
 * ("Confidential Information"). You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms of the
 * license agreement you entered into with hybris.
 * 
 *  
 */
package de.hybris.platform.cronjob.jalo;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;

import de.hybris.bootstrap.annotations.IntegrationTest;
import de.hybris.platform.core.Registry;
import de.hybris.platform.jalo.JaloItemNotFoundException;
import de.hybris.platform.jalo.type.AttributeDescriptor;
import de.hybris.platform.jalo.type.ComposedType;
import de.hybris.platform.jalo.type.JaloDuplicateCodeException;
import de.hybris.platform.jalo.type.TypeManager;
import de.hybris.platform.servicelayer.internal.jalo.ServicelayerJob;
import de.hybris.platform.testframework.HybrisJUnit4Test;
import de.hybris.platform.util.Config;
import de.hybris.platform.util.Utilities;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang.ClassUtils;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;

/**
 * It is now possible to trigger jobs directly from the trigger, without going via a cronJob. This class tests that such
 * a job can be triggered. The relationship between Trigger, Job and CronJob is now.. Job implements ITriggerableJob
 * O--------------------- O .................................| ................| | ...............................{XOR}
 * ..............| | .................................|.................| CronJob
 * O-----------------------------------------Trigger
 */
@IntegrationTest
public class TriggerableJobTest extends HybrisJUnit4Test {
    private final TypeManager typeManager = TypeManager.getInstance();
    private final CronJobManager cronJobManager = CronJobManager.getInstance();

    private static final String JOB_NOT_CHANGEABLE = "attribute 'job' is not changeable";
    private static final String CRONJOB_NOT_CHANGEABLE = "attribute 'cronJob' is not changeable";
    private static final String MISSING_CRONJOB_AND_JOB = "Cannot create trigger! No value for CronJob OR Job is given. Need only one value!";

    static int triggerPerformWaitSeconds = 10;
    static boolean backgroundThreadEnabledBefore = false;

    @BeforeClass
    public static void setUpBeforeClass() {
        // We're outside HybrisJunit4Test listeners scope so we have to activate correct tenant manually !!!
        Registry.activateStandaloneMode();
        Utilities.setJUnitTenant();

        // all test cases assume that 
        backgroundThreadEnabledBefore = disableTriggerProcessing();

        final double timeFactor = Math.max(1.0, Config.getDouble("platform.test.timefactor", 1.0));
        triggerPerformWaitSeconds = (int) (10 * timeFactor);
    }

    @AfterClass
    public static void tearDownAfterClass() {
        restoreTriggerProcessing(backgroundThreadEnabledBefore);
    }

    @Test
    public void testTriggerCanCreateAJob() throws Exception {
        //      assertTrue(TimerTaskUtils.getInstance().isRunning());

        // Assign a two second job to a trigger
        final Job job = createTwoSecondJob("job1");
        final Trigger trigger = makeTrigger(Trigger.ACTIVE, Boolean.TRUE, Trigger.ACTIVATIONTIME,
                nowMinusTSeconds(1), Trigger.JOB, job);

        // Job should not yet have a cronJob
        assertTrue("Job should have no cronjob", trigger.getJob().getCronJobs().size() == 0);

        // The trigger should not reference a cronJob directly
        assertNull("CronJob should be null", trigger.getCronJob());

        // Activate the trigger. This starts performing the job asynchronously.
        trigger.activate();

        assertEquals("Should have one cronJob", 1, trigger.getJob().getCronJobs().size());
        final CronJob cronJob = trigger.getJob().getCronJobs().iterator().next();

        assertFinished(cronJob);
    }

    @Test
    public void testTriggerNeedsAJobOrACronJobToBeInstantiated() {
        try {
            // Try to instantiate a trigger without a job or cronJob
            final Trigger trigger = makeTrigger(Trigger.ACTIVE, Boolean.TRUE, Trigger.ACTIVATIONTIME,
                    nowMinusTSeconds(1));
            // This should throw an exception
            fail("Should not be able to reach here with " + trigger);
        } catch (final Exception e) {
            // The exception should contain this string..
            assertTrue("Excepted.. " + MISSING_CRONJOB_AND_JOB + " but got " + e.getMessage() + " : "
                    + Utilities.getStackTraceAsString(e), e.getMessage().contains(MISSING_CRONJOB_AND_JOB));
        }
    }

    @Test
    public void testCanAssignCronJobToTriggerWithAJob() {
        try {
            final Job job = createTwoSecondJob("job1");
            final CronJob cronJob = cronJobManager.createCronJob(job, null, true);
            // Create a trigger with job
            final Trigger trigger = makeTrigger(Trigger.ACTIVE, Boolean.TRUE, Trigger.ACTIVATIONTIME,
                    nowMinusTSeconds(1), Trigger.JOB, job);
            // .. and try to assign cronJob to it too
            trigger.setCronJob(cronJob);
            fail();
        } catch (final Exception e) {
            // The exception should contain this string..
            assertTrue("Expected " + CRONJOB_NOT_CHANGEABLE + " but got " + e.getMessage() + " : "
                    + Utilities.getStackTraceAsString(e), e.getMessage().contains(CRONJOB_NOT_CHANGEABLE));
        }
    }

    @Test
    public void testCanAssignJobToTriggerWithACronJob() {
        try {
            final Job job = createTwoSecondJob("job1");
            final CronJob cronJob = cronJobManager.createCronJob(job, null, true);
            // Create a trigger with cronJob
            final Trigger trigger = makeTrigger(Trigger.ACTIVE, Boolean.TRUE, Trigger.ACTIVATIONTIME,
                    nowMinusTSeconds(1), Trigger.CRONJOB, cronJob);
            // .. and try to assign job to it too
            trigger.setJob(job);
            fail();
        } catch (final Exception e) {
            // The exception should contain this string..
            assertTrue("Expected " + JOB_NOT_CHANGEABLE + " but got " + e.getMessage() + " : "
                    + Utilities.getStackTraceAsString(e), e.getMessage().contains(JOB_NOT_CHANGEABLE));
        }
    }

    private Trigger makeTrigger(final Object... args) throws Exception {
        final Map<String, Object> triggerParams = new HashMap<String, Object>();
        for (int i = 0; i < args.length; i += 2) {
            triggerParams.put((String) args[i], args[i + 1]);
        }
        return (Trigger) typeManager.getComposedType(Trigger.class).newInstance(triggerParams);
    }

    private Job createTwoSecondJob(final String jobName) throws Exception {
        final Map<String, Object> jobParams = new HashMap<String, Object>();
        jobParams.put(Job.CODE, jobName + new Date());
        final ComposedType job_ct = prepareComposedTypeIfNeeded(jobName, jobParams);
        final Job newJobInstance = (Job) job_ct.newInstance(jobParams);
        Assert.assertTrue("Created job instance should be triggerable or service layer job at least ", //
                ClassUtils.isAssignable(UnPerformableJob.class, TriggerableJob.class) //
                        || //
                        ClassUtils.isAssignable(UnPerformableJob.class, ServicelayerJob.class)//
        );
        return newJobInstance;
    }

    /**
     * 
     */
    private ComposedType prepareComposedTypeIfNeeded(final String jobName, final Map<String, Object> jobParams)
            throws JaloDuplicateCodeException {
        ComposedType job_ct = null;
        try {
            job_ct = typeManager.getComposedType("TriggerableTwoSecondJob");
        } catch (final JaloItemNotFoundException e) {
            job_ct = typeManager.createComposedType(typeManager.getComposedType(ServicelayerJob.class),
                    "TriggerableTwoSecondJob");
        }
        job_ct.setJaloClass(TriggerableTwoSecondJob.class);
        return job_ct;
    }

    private Date nowMinusTSeconds(final int tSeconds) {
        return new Date(System.currentTimeMillis() - tSeconds * 1000);
    }

    @Test
    public void testPLA8101Explicity() throws Exception {
        final Job job = prepareCustomJobTypes("jobWithParams1");

        final CronJob createCronJob = job.createCronjob();

        assertEquals(job.getAttribute(CustomAttributesTriggerableJob.ATTRIBUTE_ONE_JOB_ID),
                createCronJob.getAttribute("attributeCronJobOne"));
        assertEquals(job.getAttribute(CustomAttributesTriggerableJob.ATTRIBUTE_TWO_JOB_ID),
                createCronJob.getAttribute("attributeCronJobTwo"));
        assertEquals(job.getAttribute(CustomAttributesTriggerableJob.ATTRIBUTE_THREE_JOB_ID),
                createCronJob.getAttribute("attributeCronJobThree"));

    }

    @Test
    public void testPLA8101Triggered() throws Exception {
        // Assign a two second job to a trigger
        final Job job = prepareCustomJobTypes("jobWithParams1");
        final Trigger trigger = makeTrigger(Trigger.ACTIVE, Boolean.TRUE, Trigger.ACTIVATIONTIME,
                nowMinusTSeconds(1), Trigger.JOB, job);

        // Job should not yet have a cronJob
        assertTrue("Job should have no cronjob", trigger.getJob().getCronJobs().size() == 0);

        // The trigger should not reference a cronJob directly
        assertNull("CronJob should be null", trigger.getCronJob());

        // Activate the trigger. This causes the job to instantiate a cronJob
        trigger.activate();

        assertEquals("Should have one cronJob", 1, trigger.getJob().getCronJobs().size());
        final CronJob createCronJob = trigger.getJob().getCronJobs().iterator().next();

        assertFinished(createCronJob);

        assertEquals(job.getAttribute(CustomAttributesTriggerableJob.ATTRIBUTE_ONE_JOB_ID),
                createCronJob.getAttribute(CustomAttributesTriggerableJob.ATTRIBUTE_CRON_JOB_ONE_ID));

        assertEquals(job.getAttribute(CustomAttributesTriggerableJob.ATTRIBUTE_TWO_JOB_ID),
                createCronJob.getAttribute(CustomAttributesTriggerableJob.ATTRIBUTE_CRON_JOB_TWO_ID));

        assertEquals(job.getAttribute(CustomAttributesTriggerableJob.ATTRIBUTE_THREE_JOB_ID),
                createCronJob.getAttribute(CustomAttributesTriggerableJob.ATTRIBUTE_CRON_JOB_THREE_ID));
    }

    private Job prepareCustomJobTypes(final String jobName) throws Exception {
        final Map<String, Object> jobParams = new HashMap<String, Object>();
        jobParams.put(Job.CODE, jobName + "[" + new Date() + "]");
        jobParams.put(CustomAttributesTriggerableJob.ATTRIBUTE_ONE_JOB_ID, "attributteOneValue");
        jobParams.put(CustomAttributesTriggerableJob.ATTRIBUTE_TWO_JOB_ID, "attributteTwoValue");
        jobParams.put(CustomAttributesTriggerableJob.ATTRIBUTE_THREE_JOB_ID, "attributteThreeValue");

        final ComposedType typeCronJob = typeManager.createComposedType(typeManager.getComposedType(CronJob.class),
                CustomAttributesTriggerableJob.STATICCRONJOBCODE);
        typeCronJob.createAttributeDescriptor(CustomAttributesTriggerableJob.ATTRIBUTE_CRON_JOB_ONE_ID,
                typeManager.getRootAtomicType(String.class),
                AttributeDescriptor.SEARCH_FLAG | AttributeDescriptor.WRITE_FLAG | AttributeDescriptor.READ_FLAG
                        | AttributeDescriptor.REMOVE_FLAG);
        typeCronJob.createAttributeDescriptor(CustomAttributesTriggerableJob.ATTRIBUTE_CRON_JOB_TWO_ID,
                typeManager.getRootAtomicType(String.class),
                AttributeDescriptor.SEARCH_FLAG | AttributeDescriptor.WRITE_FLAG | AttributeDescriptor.READ_FLAG
                        | AttributeDescriptor.REMOVE_FLAG);
        typeCronJob.createAttributeDescriptor(CustomAttributesTriggerableJob.ATTRIBUTE_CRON_JOB_THREE_ID,
                typeManager.getRootAtomicType(String.class),
                AttributeDescriptor.SEARCH_FLAG | AttributeDescriptor.WRITE_FLAG | AttributeDescriptor.READ_FLAG
                        | AttributeDescriptor.REMOVE_FLAG);

        final ComposedType type = typeManager.createComposedType(typeManager.getComposedType(Job.class),
                CustomAttributesTriggerableJob.STATICCJOBCODE);
        type.setJaloClass(CustomAttributesTriggerableJob.class);
        type.createAttributeDescriptor(CustomAttributesTriggerableJob.ATTRIBUTE_ONE_JOB_ID,
                typeManager.getRootAtomicType(String.class),
                AttributeDescriptor.SEARCH_FLAG | AttributeDescriptor.WRITE_FLAG | AttributeDescriptor.READ_FLAG
                        | AttributeDescriptor.REMOVE_FLAG);
        type.createAttributeDescriptor(CustomAttributesTriggerableJob.ATTRIBUTE_TWO_JOB_ID,
                typeManager.getRootAtomicType(String.class),
                AttributeDescriptor.SEARCH_FLAG | AttributeDescriptor.WRITE_FLAG | AttributeDescriptor.READ_FLAG
                        | AttributeDescriptor.REMOVE_FLAG);
        type.createAttributeDescriptor(CustomAttributesTriggerableJob.ATTRIBUTE_THREE_JOB_ID,
                typeManager.getRootAtomicType(String.class),
                AttributeDescriptor.SEARCH_FLAG | AttributeDescriptor.WRITE_FLAG | AttributeDescriptor.READ_FLAG
                        | AttributeDescriptor.REMOVE_FLAG);
        return (Job) type.newInstance(jobParams);
    }

    /*
     * PLA-7933 If the cronjob is active and the trigger is activate the cronjob/job should be performed If the cronjob
     * is NOT active the trigger should not perform the cronjob/job
     */
    @Test
    public void testPLA7933TriggerAndInactiveCronJobs() throws Exception {
        testTriggerAndDeactivatedCronJob(true);
        testTriggerAndDeactivatedCronJob(false);

    }

    private void testTriggerAndDeactivatedCronJob(final boolean activecronjob) throws Exception {
        final Job job = createTwoSecondJob("job1");
        final CronJob cronJob = cronJobManager.createCronJob(job, job.getCode() + "xxx", true);
        cronJob.setActive(activecronjob);

        final Trigger trigger = makeTrigger(Trigger.ACTIVE, Boolean.TRUE, Trigger.ACTIVATIONTIME,
                nowMinusTSeconds(1), Trigger.CRONJOB, cronJob);

        assertNull(cronJob.getStartTime());

        trigger.activate();

        if (activecronjob) {
            assertFinished(cronJob);
            assertNotNull("cronjob(active=true) was not performed!", cronJob.getStartTime());
        } else {
            waitToFinish(cronJob); // we know it won't run but we must wait for sure
            assertNull("cronjob(active=" + activecronjob + ") was performed!", cronJob.getStartTime());
        }
    }

    /**
     * PLA-7333 ,null attributes values
     */
    @Test
    public void testTriggerForNullAttributtes() throws Exception {
        TimerTaskUtils.getInstance().setDisabled(true);

        final Job job = createTwoSecondJob("job1");
        final CronJob cronJob = cronJobManager.createCronJob(job, job.getCode() + "xxx", true);
        cronJob.setActive(true);

        final Trigger trigger = makeTrigger(Trigger.ACTIVE, Boolean.TRUE, Trigger.ACTIVATIONTIME,
                nowMinusTSeconds(1), Trigger.CRONJOB, cronJob, Trigger.ACTIVATIONTIME, null, Trigger.ACTIVE, null,
                Trigger.DATERANGE, null, Trigger.DAY, null, Trigger.DAYSOFWEEK, null, Trigger.HOUR,
                null, /* Trigger.MAXACCEPTABLEDELAY, null */
                Trigger.MINUTE, null, Trigger.MONTH, null, Trigger.RELATIVE, null, Trigger.SECOND, null, /*
                                                                                                          * Trigger.TIMETABLE
                                                                                                          * , null,
                                                                                                          */
                Trigger.WEEKINTERVAL, null, Trigger.YEAR, null);
        try {
            trigger.toString();
        } catch (final Exception e) {
            fail("Unable to perform toString() on trigger [" + e.getMessage() + "] " + trigger.getPK() + " : "
                    + Utilities.getStackTraceAsString(e));
        }

    }

    private static boolean disableTriggerProcessing() {
        final TimerTaskUtils utils = TimerTaskUtils.getInstance();
        final boolean running = utils.isRunning();
        utils.setDisabled(true);

        return running;
    }

    private static void restoreTriggerProcessing(final boolean runningBefore) {
        final TimerTaskUtils utils = TimerTaskUtils.getInstance();
        utils.setDisabled(!runningBefore);
    }

    private void waitToFinish(final CronJob cronJob) {
        final Thread thread = Thread.currentThread();
        final long maxWaitTime = System.currentTimeMillis() + (triggerPerformWaitSeconds * 1000);
        while (!cronJob.isFinished() && !thread.isInterrupted() && System.currentTimeMillis() < maxWaitTime) {
            try {
                Thread.sleep(500);
            } catch (final InterruptedException e) {
                thread.interrupt();
            }
        }
    }

    private void assertFinished(final CronJob cronJob) {
        waitToFinish(cronJob);
        assertTrue(cronJob.isFinished());
    }

}