Package azkaban.flow

Source Code of azkaban.flow.IndividualJobExecutableFlowTest

package azkaban.flow;

import azkaban.app.JobManager;
import azkaban.common.jobs.Job;
import azkaban.common.utils.Props;
import azkaban.jobs.Status;

import org.easymock.IAnswer;
import org.easymock.classextension.EasyMock;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

/**
* These tests could probably be simplified by adding a "ThreadFactory" dependency on IndividualJobExecutableFlow
*
* TODO: Maybe do that?
*/
public class IndividualJobExecutableFlowTest
{
    private volatile JobManager jobManager;

    private volatile AtomicBoolean assertionViolated;
    private volatile String reason;

    private static Throwable theException;
    private static Map<String,Throwable> theExceptions;
    private static Map<String, Throwable> emptyExceptions;
   
    @BeforeClass
    public static void init() throws Exception {
      theException = new RuntimeException();
      theExceptions = new HashMap<String,Throwable>();
      theExceptions.put("blah", theException);
      emptyExceptions = new HashMap<String, Throwable>();
    }
   
    @Before
    public void setUp()
    {
        jobManager = EasyMock.createMock(JobManager.class);

        assertionViolated = new AtomicBoolean(false);
        reason = "Default Reason";
    }

    @After
    public void tearDown()
    {
        Assert.assertFalse(reason, assertionViolated.get());
        EasyMock.verify(jobManager);
    }

   
    @Test
    public void testSanity() throws Throwable
    {
        final CountDownLatch completionLatch = new CountDownLatch(1);

        final Job mockJob = EasyMock.createMock(Job.class);
        final Props overrideProps = new Props();
        final IndividualJobExecutableFlow executableFlow = new IndividualJobExecutableFlow("blah", "blah", jobManager);

        EasyMock.expect(jobManager.loadJob("blah", overrideProps, true)).andReturn(mockJob).once();
        EasyMock.expect(mockJob.getId()).andReturn("success Job").once();

        mockJob.run();
        EasyMock.expectLastCall().andAnswer(new IAnswer<Void>()
        {
            @Override
            public Void answer() throws Throwable
            {
                Assert.assertEquals(Status.RUNNING, executableFlow.getStatus());

                return null;
            }
        }).once();

        final Props returnProps = new Props();
        EasyMock.expect(mockJob.getJobGeneratedProperties()).andReturn(returnProps).once();

        EasyMock.replay(mockJob, jobManager);

        Assert.assertEquals(Status.READY, executableFlow.getStatus());

        executableFlow.execute(
                overrideProps,
                new FlowCallback()
                {
                    @Override
                    public void progressMade()
                    {
                        assertionViolated.set(true);
                        reason = String.format("progressMade() shouldn't actually be called.");
                    }

                    @Override
                    public void completed(Status status)
                    {
                        completionLatch.countDown();
                        if (Status.SUCCEEDED != status) {
                            assertionViolated.set(true);
                            reason = String.format("In executableFlow Callback: status[%s] != Status.SUCCEEDED", status);
                        }
                    }
                });

        completionLatch.await(1000, TimeUnit.MILLISECONDS);
        Assert.assertEquals(Status.SUCCEEDED, executableFlow.getStatus());
        Assert.assertEquals(emptyExceptions, executableFlow.getExceptions());
        Assert.assertEquals(overrideProps, executableFlow.getParentProps());
        Assert.assertEquals(returnProps, executableFlow.getReturnProps());

        Props otherProps = new Props();
        otherProps.put("billy", "blank");

        boolean exceptionThrown = false;
        try {
            executableFlow.execute(
                    otherProps,
                    new FlowCallback() {
                        @Override
                        public void progressMade() {
                        }

                        @Override
                        public void completed(Status status) {
                        }
                    }
            );
        }
        catch (IllegalArgumentException e) {
            exceptionThrown = true;
        }

        EasyMock.verify(mockJob);

        Assert.assertTrue("Expected an IllegalArgumentException to be thrown because props weren't the same.", exceptionThrown);
        Assert.assertTrue("Expected to be able to reset the executableFlow.", executableFlow.reset());
        Assert.assertEquals(Status.READY, executableFlow.getStatus());
        Assert.assertEquals(null, executableFlow.getReturnProps());
        Assert.assertEquals(null, executableFlow.getParentProps());
    }


    @Test
    public void testFailure() throws Throwable
    {
               
        final CountDownLatch completionLatch = new CountDownLatch(1);

        final Job mockJob = EasyMock.createMock(Job.class);
        final Props overrideProps = new Props();
        final IndividualJobExecutableFlow executableFlow = new IndividualJobExecutableFlow("blah", "blah", jobManager);

        EasyMock.expect(jobManager.loadJob("blah", overrideProps, true)).andReturn(mockJob).once();
        EasyMock.expect(mockJob.getId()).andReturn("blah").times(1);
       
       
        mockJob.run();
        EasyMock.expectLastCall().andAnswer(new IAnswer<Void>()
        {
            @Override
            public Void answer() throws Throwable
            {
                Assert.assertEquals(Status.RUNNING, executableFlow.getStatus());
                throw theException;
            }
        }).once();
       
        EasyMock.replay(mockJob, jobManager);

        Assert.assertEquals(Status.READY, executableFlow.getStatus());
        Assert.assertEquals(emptyExceptions, executableFlow.getExceptions());

        executableFlow.execute(
                overrideProps,
                new FlowCallback()
                {
                    @Override
                    public void progressMade()
                    {
                        assertionViolated.set(true);
                        reason = String.format("progressMade() shouldn't actually be called.");
                    }

                    @Override
                    public void completed(Status status)
                    {
                        completionLatch.countDown();
                        if (Status.FAILED != status) {
                            assertionViolated.set(true);
                            reason = String.format("In executableFlow Callback: status[%s] != Status.FAILED", status);
                        }
                    }
                });

        completionLatch.await(1000, TimeUnit.MILLISECONDS);
        Assert.assertEquals(Status.FAILED, executableFlow.getStatus());
        Assert.assertEquals(theExceptions, executableFlow.getExceptions());

        EasyMock.verify(mockJob);

        Assert.assertTrue("Expected to be able to reset the executableFlow.", executableFlow.reset());
        Assert.assertEquals(Status.READY, executableFlow.getStatus());
        Assert.assertEquals(emptyExceptions, executableFlow.getExceptions());
    }

   
    @Test
    public void testNoChildren() throws Exception
    {
        EasyMock.replay(jobManager);
        final IndividualJobExecutableFlow executableFlow = new IndividualJobExecutableFlow("blah", "blah", jobManager);

        Assert.assertFalse("IndividualJobExecutableFlow objects should not have any children.", executableFlow.hasChildren());
        Assert.assertTrue("IndividualJobExecutableFlow objects should not return any children.", executableFlow.getChildren().isEmpty());
    }

   
    @Test
    public void testAllExecuteCallbacksCalledOnSuccess() throws Throwable
    {
        final CountDownLatch firstCallbackLatch = new CountDownLatch(1);
        final CountDownLatch secondCallbackLatch = new CountDownLatch(1);

        final Job mockJob = EasyMock.createMock(Job.class);
        final Props overrideProps = new Props();
        final IndividualJobExecutableFlow executableFlow = new IndividualJobExecutableFlow("blah", "blah", jobManager);

        EasyMock.expect(jobManager.loadJob("blah", overrideProps, true)).andReturn(mockJob).once();
        EasyMock.expect(mockJob.getId()).andReturn("success Job").once();

        mockJob.run();
        EasyMock.expectLastCall().andAnswer(new IAnswer<Void>()
        {
            @Override
            public Void answer() throws Throwable
            {
                Assert.assertEquals(Status.RUNNING, executableFlow.getStatus());

                return null;
            }
        }).once();

        final Props returnProps = new Props();
        EasyMock.expect(mockJob.getJobGeneratedProperties()).andReturn(returnProps).once();

        EasyMock.replay(mockJob, jobManager);

        Assert.assertEquals(Status.READY, executableFlow.getStatus());

        final AtomicBoolean firstCallbackCalled = new AtomicBoolean(false);
        executableFlow.execute(
                overrideProps,
                new OneCallFlowCallback(firstCallbackCalled)
                {
                    @Override
                    public void theCallback(Status status)
                    {
                        firstCallbackLatch.countDown();
                        if (Status.SUCCEEDED != status) {
                            assertionViolated.set(true);
                            reason = String.format("In executableFlow Callback1: status[%s] != Status.SUCCEEDED", status);
                        }
                    }
                });

        final AtomicBoolean secondCallbackCalled = new AtomicBoolean(false);
        executableFlow.execute(
                overrideProps,
                new OneCallFlowCallback(secondCallbackCalled)
                {
                    @Override
                    public void theCallback(Status status)
                    {
                        secondCallbackLatch.countDown();
                        if (Status.SUCCEEDED != status) {
                            assertionViolated.set(true);
                            reason = String.format("In executableFlow Callback2: status[%s] != Status.SUCCEEDED", status);
                        }
                    }
                });

        firstCallbackLatch.await(1000, TimeUnit.MILLISECONDS);
        secondCallbackLatch.await(1000, TimeUnit.MILLISECONDS);
        Assert.assertEquals(Status.SUCCEEDED, executableFlow.getStatus());
        Assert.assertEquals(emptyExceptions, executableFlow.getExceptions());
        Assert.assertEquals(overrideProps, executableFlow.getParentProps());
        Assert.assertEquals(returnProps, executableFlow.getReturnProps());

        EasyMock.verify(mockJob);

        Assert.assertTrue("First callback wasn't called?", firstCallbackCalled.get());
        Assert.assertTrue("Second callback wasn't called?", secondCallbackCalled.get());
        Assert.assertTrue("Expected to be able to reset the executableFlow.", executableFlow.reset());
        Assert.assertEquals(Status.READY, executableFlow.getStatus());
        Assert.assertEquals(null, executableFlow.getParentProps());
        Assert.assertEquals(null, executableFlow.getReturnProps());
    }

   
    @Test
    public void testAllExecuteCallbacksCalledOnFailure() throws Throwable
    {
        final CountDownLatch firstCallbackLatch = new CountDownLatch(1);
        final CountDownLatch secondCallbackLatch = new CountDownLatch(1);

        final Job mockJob = EasyMock.createMock(Job.class);
        final Props overrideProps = new Props();
        final IndividualJobExecutableFlow executableFlow = new IndividualJobExecutableFlow("blah", "blah", jobManager);

        EasyMock.expect(jobManager.loadJob("blah", overrideProps, true)).andReturn(mockJob).once();
        EasyMock.expect(mockJob.getId()).andReturn("blah").times(1);

        mockJob.run();
        EasyMock.expectLastCall().andThrow(theException).once();

        EasyMock.replay(mockJob, jobManager);

        Assert.assertEquals(Status.READY, executableFlow.getStatus());

        final AtomicBoolean firstCallbackCalled = new AtomicBoolean(false);
        executableFlow.execute(
                overrideProps,
                new OneCallFlowCallback(firstCallbackCalled)
                {
                    @Override
                    public void theCallback(Status status)
                    {
                        firstCallbackLatch.countDown();
                        if (Status.FAILED != status) {
                            assertionViolated.set(true);
                            reason = String.format("In executableFlow Callback1: status[%s] != Status.FAILED", status);
                        }
                    }
                });

        final AtomicBoolean secondCallbackCalled = new AtomicBoolean(false);
        executableFlow.execute(
                overrideProps,
                new OneCallFlowCallback(secondCallbackCalled)
                {
                    @Override
                    public void theCallback(Status status)
                    {
                        secondCallbackLatch.countDown();
                        if (Status.FAILED != status) {
                            assertionViolated.set(true);
                            reason = String.format("In executableFlow Callback2: status[%s] != Status.FAILED", status);
                        }
                    }
                });

        firstCallbackLatch.await(1000, TimeUnit.MILLISECONDS);
        secondCallbackLatch.await(1000, TimeUnit.MILLISECONDS);
        Assert.assertEquals(Status.FAILED, executableFlow.getStatus());
        Assert.assertEquals(theExceptions, executableFlow.getExceptions());

        EasyMock.verify(mockJob);

        Assert.assertTrue("First callback wasn't called?", firstCallbackCalled.get());
        Assert.assertTrue("Second callback wasn't called?", secondCallbackCalled.get());
        Assert.assertTrue("Expected to be able to reset the executableFlow.", executableFlow.reset());
        Assert.assertEquals(Status.READY, executableFlow.getStatus());
        Assert.assertEquals(emptyExceptions, executableFlow.getExceptions());

    }

   
    @Test
    public void testReset() throws Exception
    {
        final CountDownLatch completionLatch = new CountDownLatch(1);

        final Job mockJob = EasyMock.createMock(Job.class);
        final Props overrideProps = new Props();
        final IndividualJobExecutableFlow executableFlow = new IndividualJobExecutableFlow("blah", "blah", jobManager);

        final Props firstProps = new Props();
        final Props secondProps = new Props();

        EasyMock.expect(jobManager.loadJob("blah", overrideProps, true)).andReturn(mockJob).once();
        EasyMock.expect(mockJob.getId()).andReturn("success Job").once();
        EasyMock.expect(mockJob.getJobGeneratedProperties()).andReturn(firstProps).once();

        mockJob.run();
        EasyMock.expectLastCall().andAnswer(new IAnswer<Void>()
        {
            @Override
            public Void answer() throws Throwable
            {
                Assert.assertEquals(Status.RUNNING, executableFlow.getStatus());

                return null;
            }
        }).once();

        EasyMock.replay(mockJob, jobManager);

        Assert.assertEquals(Status.READY, executableFlow.getStatus());

        executableFlow.execute(
                overrideProps,
                new FlowCallback()
                {
                    @Override
                    public void progressMade()
                    {
                        assertionViolated.set(true);
                        reason = String.format("progressMade() shouldn't actually be called.");
                    }

                    @Override
                    public void completed(Status status)
                    {
                        completionLatch.countDown();
                        if (Status.SUCCEEDED != status) {
                            assertionViolated.set(true);
                            reason = String.format("In executableFlow Callback: status[%s] != Status.SUCCEEDED", status);
                        }
                    }
                });

        completionLatch.await(1000, TimeUnit.MILLISECONDS);
        Assert.assertEquals(Status.SUCCEEDED, executableFlow.getStatus());
        Assert.assertEquals(emptyExceptions, executableFlow.getExceptions());
        Assert.assertEquals(firstProps, executableFlow.getReturnProps());

        EasyMock.verify(mockJob, jobManager);
        EasyMock.reset(mockJob, jobManager);

        final CountDownLatch completionLatch2 = new CountDownLatch(1);

        Assert.assertTrue("Expected to be able to reset the executableFlow.", executableFlow.reset());
        Assert.assertEquals(Status.READY, executableFlow.getStatus());
        Assert.assertEquals(null, executableFlow.getParentProps());
        Assert.assertEquals(null, executableFlow.getReturnProps());

        EasyMock.expect(jobManager.loadJob("blah", overrideProps, true)).andReturn(mockJob).once();
        EasyMock.expect(mockJob.getId()).andReturn("success Job").once();
        EasyMock.expect(mockJob.getJobGeneratedProperties()).andReturn(secondProps).once();

        mockJob.run();
        EasyMock.expectLastCall().andAnswer(new IAnswer<Void>()
        {
            @Override
            public Void answer() throws Throwable
            {
                Assert.assertEquals(Status.RUNNING, executableFlow.getStatus());

                return null;
            }
        }).once();

        EasyMock.replay(mockJob, jobManager);

        Assert.assertEquals(Status.READY, executableFlow.getStatus());

        executableFlow.execute(
                overrideProps,
                new FlowCallback()
                {
                    @Override
                    public void progressMade()
                    {
                        assertionViolated.set(true);
                        reason = String.format("progressMade() shouldn't actually be called.");
                    }

                    @Override
                    public void completed(Status status)
                    {
                        completionLatch2.countDown();
                        if (Status.SUCCEEDED != status) {
                            assertionViolated.set(true);
                            reason = String.format("In executableFlow Callback: status[%s] != Status.SUCCEEDED", status);
                        }
                    }
                });

        completionLatch2.await(1000, TimeUnit.MILLISECONDS);
        Assert.assertEquals(Status.SUCCEEDED, executableFlow.getStatus());
        Assert.assertEquals(emptyExceptions, executableFlow.getExceptions());
        Assert.assertEquals(overrideProps, executableFlow.getParentProps());
        Assert.assertEquals(secondProps, executableFlow.getReturnProps());

        EasyMock.verify(mockJob);
    }

    @Test
    public void testResetWithFailedJob() throws Exception
    {
        final CountDownLatch completionLatch = new CountDownLatch(1);

        final Job mockJob = EasyMock.createMock(Job.class);
        final Props overrideProps = new Props();
        final IndividualJobExecutableFlow executableFlow = new IndividualJobExecutableFlow("blah", "blah", jobManager);
        executableFlow.setStatus(Status.FAILED);

        Assert.assertTrue("Should be able to reset the flow.", executableFlow.reset());

        EasyMock.expect(jobManager.loadJob("blah", overrideProps, true)).andReturn(mockJob).once();
        EasyMock.expect(mockJob.getId()).andReturn("success Job").once();

        mockJob.run();
        EasyMock.expectLastCall().andAnswer(new IAnswer<Void>()
        {
            @Override
            public Void answer() throws Throwable
            {
                Assert.assertEquals(Status.RUNNING, executableFlow.getStatus());

                return null;
            }
        }).once();

        EasyMock.expect(mockJob.getJobGeneratedProperties()).andReturn(new Props()).once();

        EasyMock.replay(mockJob, jobManager);

        Assert.assertEquals(Status.READY, executableFlow.getStatus());

        executableFlow.execute(
                overrideProps,
                new FlowCallback()
                {
                    @Override
                    public void progressMade()
                    {
                        assertionViolated.set(true);
                        reason = String.format("progressMade() shouldn't actually be called.");
                    }

                    @Override
                    public void completed(Status status)
                    {
                        completionLatch.countDown();
                        if (Status.SUCCEEDED != status) {
                            assertionViolated.set(true);
                            reason = String.format("In executableFlow Callback: status[%s] != Status.SUCCEEDED", status);
                        }
                    }
                });

        completionLatch.await(1000, TimeUnit.MILLISECONDS);
        Assert.assertEquals(Status.SUCCEEDED, executableFlow.getStatus());

        EasyMock.verify(mockJob);
    }

    @Test
    public void testCancel() throws Exception
    {
        final CountDownLatch cancelLatch = new CountDownLatch(1);
        final CountDownLatch runLatch = new CountDownLatch(1);

        final Job mockJob = EasyMock.createMock(Job.class);
        final Props overrideProps = new Props();
        final IndividualJobExecutableFlow executableFlow = new IndividualJobExecutableFlow("blah", "blah", jobManager);

        Assert.assertTrue("Should be able to reset the flow.", executableFlow.reset());

        EasyMock.expect(mockJob.getId()).andReturn("blah").once();
        mockJob.run();
        EasyMock.expect(jobManager.loadJob("blah", overrideProps, true)).andAnswer(new IAnswer<Job>()
        {
            @Override
            public Job answer() throws Throwable
            {
                cancelLatch.countDown();
                runLatch.await();

                return mockJob;
            }
        }).once();

        EasyMock.expect(mockJob.getJobGeneratedProperties()).andReturn(new Props()).once();
       
        EasyMock.replay(mockJob, jobManager);

        new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                try {
                    cancelLatch.await();
                }
                catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }

                if(! executableFlow.cancel()) {
                    assertionViolated.set(true);
                    reason = "In cancel thread: call to cancel returned false.";
                }

                runLatch.countDown();
            }
        }).start();

        AtomicBoolean runOnce = new AtomicBoolean(false);
        executableFlow.execute(
                overrideProps,
                new OneCallFlowCallback(runOnce)
                {
                    @Override
                    protected void theCallback(Status status)
                    {
                        if (status != Status.FAILED) {
                            assertionViolated.set(true);
                            reason = String.format("In executableFlow callback: status[%s] != Status.FAILED", status);
                            return;
                        }

                        if (! (runLatch.getCount() == 1 && cancelLatch.getCount() == 0)) {
                            assertionViolated.set(true);
                            reason = String.format(
                                    "In executableFlow callback: ! (runLatch.count[%s] == 1 && cancelLatch.count[%s] == 0)",
                                    runLatch.getCount(),
                                    cancelLatch.getCount()
                            );
                        }
                    }
                });

        Assert.assertTrue("Expected callback to be called once.", runOnce.get());
        Assert.assertEquals(0, executableFlow.getReturnProps().size());
    }
}
TOP

Related Classes of azkaban.flow.IndividualJobExecutableFlowTest

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.