From 6e05ea93d722fe8604fefbe48c40da824299fcef Mon Sep 17 00:00:00 2001 From: Mark Waite Date: Mon, 27 Jan 2025 13:36:01 -0700 Subject: [PATCH] Extend mock tests to cover more branches --- pom.xml | 15 ++ ...onfigurationPlaceholderTaskHelperTest.java | 235 ++++++++++++------ 2 files changed, 180 insertions(+), 70 deletions(-) diff --git a/pom.xml b/pom.xml index fd425fb3..544d612f 100644 --- a/pom.xml +++ b/pom.xml @@ -120,6 +120,21 @@ 1.28 test + + org.jenkins-ci.plugins.workflow + workflow-basic-steps + test + + + org.jenkins-ci.plugins.workflow + workflow-cps + test + + + org.jenkins-ci.plugins.workflow + workflow-job + test + org.mockito mockito-core diff --git a/src/test/java/jenkins/advancedqueue/PriorityConfigurationPlaceholderTaskHelperTest.java b/src/test/java/jenkins/advancedqueue/PriorityConfigurationPlaceholderTaskHelperTest.java index 9db780ce..0fadef02 100644 --- a/src/test/java/jenkins/advancedqueue/PriorityConfigurationPlaceholderTaskHelperTest.java +++ b/src/test/java/jenkins/advancedqueue/PriorityConfigurationPlaceholderTaskHelperTest.java @@ -1,23 +1,29 @@ package jenkins.advancedqueue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.startsWith; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import hudson.model.Action; -import hudson.model.Descriptor; -import hudson.model.FreeStyleProject; -import hudson.model.ParametersAction; +import hudson.model.Cause; import hudson.model.Queue; -import hudson.model.StringParameterValue; -import java.io.IOException; -import java.util.Arrays; -import java.util.Calendar; +import java.util.ArrayList; +import java.util.List; import jenkins.advancedqueue.priority.PriorityStrategy; +import jenkins.advancedqueue.sorter.SorterStrategy; +import jenkins.advancedqueue.sorter.SorterStrategyCallback; import jenkins.advancedqueue.sorter.strategy.MultiBucketStrategy; +import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; +import org.jenkinsci.plugins.workflow.job.WorkflowJob; import org.jenkinsci.plugins.workflow.support.steps.ExecutorStepExecution; +import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Test; @@ -28,98 +34,187 @@ public class PriorityConfigurationPlaceholderTaskHelperTest { @ClassRule public static JenkinsRule j = new JenkinsRule(); - private static PriorityStrategy strategy; - private static Queue.Item item; - private static FreeStyleProject project; - private static Action action; - private static PriorityConfigurationCallback callback; - private static PriorityConfigurationPlaceholderTaskHelper helper; - private static Queue.Task ownerTask; - private static ExecutorStepExecution.PlaceholderTask task; + private static Queue.Item pipelineItemInQuietPeriod; + private static DecisionLogger decisionLogger; + private static List loggedMessages; @BeforeClass - public static void setUp() throws IOException { - project = j.createFreeStyleProject(); - helper = new PriorityConfigurationPlaceholderTaskHelper(); - task = mock(ExecutorStepExecution.PlaceholderTask.class); - ownerTask = mock(Queue.Task.class); + public static void startPipelineJobWithQuietPeriod() throws Exception { + // Start a Pipeline with a quiet period of 37 seconds before it runs + String pipelineName = "my-pipeline-in-the-quiet-period"; + WorkflowJob pipeline = j.createProject(WorkflowJob.class, pipelineName); + String pipelineDefinition = + """ + node { + echo 'Hello from a node' + sleep 41 + } + """; + pipeline.setDefinition(new CpsFlowDefinition(pipelineDefinition, true)); + pipeline.scheduleBuild(37, new Cause.UserIdCause()); + pipelineItemInQuietPeriod = findQueueItem(pipelineName); + assertNotNull("Pipeline in quiet period not in Queue", pipelineItemInQuietPeriod); + // Check the item is blocked due to the 37 second quiet period + assertThat( + pipelineItemInQuietPeriod.getCauseOfBlockage().getShortDescription(), + startsWith("In the quiet period.")); } - @BeforeClass - public static void createActionAndItem() { - action = new ParametersAction(new StringParameterValue("priority", "5")); - item = new Queue.WaitingItem(Calendar.getInstance(), project, Arrays.asList(action)); - } - - @BeforeClass - public static void createStrategy() { - strategy = new PriorityStrategy() { - @Override - public boolean isApplicable(Queue.Item item) { - return false; - } - - @Override - public int getPriority(Queue.Item item) { - return 3; - } - - @Override - public void numberPrioritiesUpdates(int oldNumberOfPriorities, int newNumberOfPriorities) {} - - @Override - public Descriptor getDescriptor() { - return null; + private static Queue.Item findQueueItem(String name) { + Queue.Item found = null; + Queue.Item[] items = j.jenkins.getQueue().getItems(); + for (Queue.Item item : items) { + if (item.getDisplayName().equals(name)) { + found = item; } - }; + } + return found; } @BeforeClass - public static void createCallback() { - callback = new PriorityConfigurationCallback() { + public static void createDecisionLogger() { + decisionLogger = new DecisionLogger() { @Override public DecisionLogger addDecisionLog(int indent, String log) { - return null; - } - - @Override - public PriorityConfigurationCallback setPrioritySelection(int priority) { - return null; + loggedMessages.add(log); + return this; } + }; + } - @Override - public PriorityConfigurationCallback setPrioritySelection( - int priority, int jobGroupId, PriorityStrategy reason) { - return null; - } + @Before + public void clearLoggedMessages() throws Exception { + loggedMessages = new ArrayList<>(); + } - @Override - public PriorityConfigurationCallback setPrioritySelection( - int priority, long sortAsInQueueSince, int jobGroupId, PriorityStrategy reason) { - return null; - } - }; + @Test + public void testGetPriorityAssignsGlobalDefault() { + PriorityConfiguration configuration = new PriorityConfiguration(); + PriorityConfigurationCallbackImpl callback = new PriorityConfigurationCallbackImpl(); + assertThat(callback.getPrioritySelection(), is(-1)); // Before callback is used + configuration.getPriority(pipelineItemInQuietPeriod, callback); + assertThat(loggedMessages, hasItem("Assigning global default priority")); + assertThat(callback.getPrioritySelection(), is(MultiBucketStrategy.DEFAULT_PRIORITY)); // After callback is used } @Test public void testIsPlaceholderTask() { - Queue.Task myTask = mock(ExecutorStepExecution.PlaceholderTask.class); - assertTrue(helper.isPlaceholderTask(myTask)); + PriorityConfigurationPlaceholderTaskHelper helper = new PriorityConfigurationPlaceholderTaskHelper(); + // Pipeline task is not a placeholder task + assertFalse(helper.isPlaceholderTask(pipelineItemInQuietPeriod.getTask())); } @Test public void testGetPriority() { + // Could not find an easy way to generate a placeholder task + // Use a mock object for better test coverage + ExecutorStepExecution.PlaceholderTask task = mock(ExecutorStepExecution.PlaceholderTask.class); + when(task.getOwnerTask()).thenReturn(pipelineItemInQuietPeriod.getTask()); + + PriorityConfigurationPlaceholderTaskHelper helper = new PriorityConfigurationPlaceholderTaskHelper(); + PriorityConfigurationCallbackImpl callback = new PriorityConfigurationCallbackImpl(); + assertThat(callback.getPrioritySelection(), is(-1)); // Before callback is used + callback.expectPrioritySelection(3); + PriorityConfigurationCallback result = helper.getPriority(task, callback); + assertNotNull(result); + + // Verify that the default priority from the MultiBucketStrategy is returned by the strategy for the given item + assertEquals(MultiBucketStrategy.DEFAULT_PRIORITY, callback.getPrioritySelection()); + } + + @Test + public void testGetPriorityNonJobTask() { + // Could not find an easy way to generate a placeholder task + // Use a mock object for better test coverage + ExecutorStepExecution.PlaceholderTask task = mock(ExecutorStepExecution.PlaceholderTask.class); + Queue.Task ownerTask = mock(Queue.Task.class); when(task.getOwnerTask()).thenReturn(ownerTask); + // Use a custom sorter strategy + SorterStrategyImpl strategy = new SorterStrategyImpl(); + PrioritySorterConfiguration.get().setStrategy(strategy); + + PriorityConfigurationPlaceholderTaskHelper helper = new PriorityConfigurationPlaceholderTaskHelper(); + PriorityConfigurationCallbackImpl callback = new PriorityConfigurationCallbackImpl(); + assertThat(callback.getPrioritySelection(), is(-1)); // Before callback is used + // Check that default priority of custom strategy is different than system-wide default priority + assertThat(strategy.getDefaultPriority(), is(not(MultiBucketStrategy.DEFAULT_PRIORITY))); + callback.expectPrioritySelection(strategy.getDefaultPriority()); PriorityConfigurationCallback result = helper.getPriority(task, callback); assertNotNull(result); - // Verify that the default priority from the MultiBucketStrategy is returned by the strategy for the given item - assertEquals(MultiBucketStrategy.DEFAULT_PRIORITY, strategy.getPriority(item)); + // Verify that the default priority from the strategy is returned + assertEquals(strategy.getDefaultPriority(), callback.getPrioritySelection()); } @Test public void testIsPlaceholderTaskUsed() { assertTrue(PriorityConfigurationPlaceholderTaskHelper.isPlaceholderTaskUsed()); } + + private static class PriorityConfigurationCallbackImpl implements PriorityConfigurationCallback { + + private int prioritySelection = -1; + private int expectedPrioritySelection = -1; + + public PriorityConfigurationCallbackImpl() {} + + private int getPrioritySelection() { + return prioritySelection; + } + + @Override + public PriorityConfigurationCallback setPrioritySelection(int priority) { + prioritySelection = priority; + if (expectedPrioritySelection != -1) { + assertThat(priority, is(expectedPrioritySelection)); + } + return this; + } + + @Override + public PriorityConfigurationCallback setPrioritySelection( + int priority, int jobGroupId, PriorityStrategy reason) { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public PriorityConfigurationCallback setPrioritySelection( + int priority, long sortAsInQueueSince, int jobGroupId, PriorityStrategy reason) { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public DecisionLogger addDecisionLog(int indent, String log) { + decisionLogger.addDecisionLog(indent, log); + return decisionLogger; + } + + private void expectPrioritySelection(int priority) { + expectedPrioritySelection = priority; + } + } + + /* A sorter strategy that is intentionally different than the default */ + private static class SorterStrategyImpl extends SorterStrategy { + + private final int NUMBER_OF_PRIORITIES = 4 + MultiBucketStrategy.DEFAULT_PRIORITIES_NUMBER; + + public SorterStrategyImpl() {} + + @Override + public SorterStrategyCallback onNewItem(Queue.Item item, SorterStrategyCallback weightCallback) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getNumberOfPriorities() { + return NUMBER_OF_PRIORITIES; + } + + @Override + public int getDefaultPriority() { + return NUMBER_OF_PRIORITIES / 2; + } + } }