| /* |
| * Copyright 2009 Google Inc. |
| * |
| * 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 com.google.gwt.core.client.impl; |
| |
| import com.google.gwt.core.client.Duration; |
| import com.google.gwt.core.client.JsArray; |
| import com.google.gwt.core.client.Scheduler.RepeatingCommand; |
| import com.google.gwt.core.client.Scheduler.ScheduledCommand; |
| import com.google.gwt.core.client.impl.SchedulerImpl.Task; |
| import com.google.gwt.junit.client.GWTTestCase; |
| |
| /** |
| * This is a white-box test of the Scheduler API implementation. |
| */ |
| public class SchedulerImplTest extends GWTTestCase { |
| |
| static class ArraySetterCommand implements ScheduledCommand { |
| private final boolean[] values; |
| |
| public ArraySetterCommand(boolean[] values) { |
| this.values = values; |
| } |
| |
| @Override |
| public void execute() { |
| values[0] = true; |
| } |
| } |
| |
| static class CountingCommand implements RepeatingCommand { |
| public final int[] values; |
| |
| public CountingCommand(int[] values) { |
| assertEquals(2, values.length); |
| this.values = values; |
| } |
| |
| @Override |
| public boolean execute() { |
| assertTrue("Called too many times", values[0] < values[1]); |
| values[0] = values[0] + 1; |
| return values[0] < values[1]; |
| } |
| } |
| |
| /** |
| * A no-op command used to test internal datastructures. |
| */ |
| static class NullCommand implements ScheduledCommand { |
| @Override |
| public void execute() { |
| } |
| } |
| |
| /** |
| * The EntryCommand and FinallyCommand queues should have the same behavior, |
| * so we use this interface to reuse the same test logic. |
| */ |
| interface QueueTester { |
| void flush(); |
| |
| JsArray<Task> queue(); |
| |
| void schedule(RepeatingCommand cmd); |
| |
| void schedule(ScheduledCommand cmd); |
| } |
| |
| private static class RepeatingCommandImpl implements RepeatingCommand { |
| private boolean firstTime = true; |
| private boolean commandRanSecondTime = false; |
| |
| @Override |
| public boolean execute() { |
| // Command needs to run for the second time to be executed in runScheduledTasks |
| if (firstTime) { |
| firstTime = false; |
| return true; |
| } |
| commandRanSecondTime = true; |
| return false; |
| } |
| } |
| |
| private static final int TEST_DELAY = 5000; |
| |
| @Override |
| public String getModuleName() { |
| return "com.google.gwt.core.Core"; |
| } |
| |
| public void testDeferredCommands() { |
| final SchedulerImpl impl = new SchedulerImpl(); |
| |
| final boolean[] values = {false}; |
| impl.scheduleDeferred(new ArraySetterCommand(values)); |
| |
| assertEquals(1, impl.deferredCommands.length()); |
| |
| ScheduledCommand nullCommand = new NullCommand(); |
| impl.scheduleDeferred(nullCommand); |
| assertEquals(2, impl.deferredCommands.length()); |
| assertSame(nullCommand, impl.deferredCommands.get(1).getScheduled()); |
| |
| impl.scheduleDeferred(new ScheduledCommand() { |
| @Override |
| public void execute() { |
| assertTrue(values[0]); |
| assertNull(impl.deferredCommands); |
| finishTest(); |
| } |
| }); |
| |
| delayTestFinish(TEST_DELAY); |
| } |
| |
| /** |
| * This test could potentially timeout since loop in {@link SchedulerImpl#runRepeatingTasks} would |
| * run indefinitely since we are mocking Duration to always return zero. |
| * |
| * see for details: https://code.google.com/p/google-web-toolkit/issues/detail?id=7307 |
| */ |
| public void testEarlyBreakIfAllTaskAreFinished() { |
| final SchedulerImpl impl = new SchedulerImpl() { |
| @Override |
| Duration createDuration() { |
| return new Duration() { |
| @Override |
| public int elapsedMillis() { |
| // never expire |
| return 0; |
| } |
| }; |
| } |
| }; |
| |
| final RepeatingCommandImpl command = new RepeatingCommandImpl(); |
| |
| impl.scheduleIncremental(command); |
| |
| impl.scheduleDeferred(new ScheduledCommand() { |
| @Override |
| public void execute() { |
| |
| if (command.commandRanSecondTime) { |
| finishTest(); |
| } else { |
| impl.scheduleDeferred(this); |
| } |
| } |
| }); |
| |
| delayTestFinish(TEST_DELAY); |
| } |
| |
| public void testEntryCommands() { |
| final SchedulerImpl impl = new SchedulerImpl(); |
| |
| testQueue(new QueueTester() { |
| @Override |
| public void flush() { |
| impl.flushEntryCommands(); |
| } |
| |
| @Override |
| public JsArray<Task> queue() { |
| return impl.entryCommands; |
| } |
| |
| @Override |
| public void schedule(RepeatingCommand cmd) { |
| impl.scheduleEntry(cmd); |
| } |
| |
| @Override |
| public void schedule(ScheduledCommand cmd) { |
| impl.scheduleEntry(cmd); |
| } |
| }); |
| } |
| |
| public void testFinallyCommands() { |
| final SchedulerImpl impl = new SchedulerImpl(); |
| |
| testQueue(new QueueTester() { |
| @Override |
| public void flush() { |
| impl.flushFinallyCommands(); |
| } |
| |
| @Override |
| public JsArray<Task> queue() { |
| return impl.finallyCommands; |
| } |
| |
| @Override |
| public void schedule(RepeatingCommand cmd) { |
| impl.scheduleFinally(cmd); |
| } |
| |
| @Override |
| public void schedule(ScheduledCommand cmd) { |
| impl.scheduleFinally(cmd); |
| } |
| }); |
| } |
| |
| public void testFixedDelayCommands() { |
| final SchedulerImpl impl = new SchedulerImpl(); |
| final int[] values = {0, 4}; |
| |
| impl.scheduleFixedDelay(new CountingCommand(values), 20); |
| // Scheduler doesn't need to maintain state for this kind of command |
| assertFalse(impl.isWorkQueued()); |
| |
| // Busy wait for the counter |
| impl.scheduleDeferred(new ScheduledCommand() { |
| @Override |
| public void execute() { |
| if (values[0] == values[1]) { |
| finishTest(); |
| } else { |
| impl.scheduleDeferred(this); |
| } |
| } |
| }); |
| |
| delayTestFinish(TEST_DELAY); |
| } |
| |
| public void testFixedPeriodCommands() { |
| final SchedulerImpl impl = new SchedulerImpl(); |
| final int[] values = {0, 4}; |
| |
| impl.scheduleFixedPeriod(new CountingCommand(values), 20); |
| // Scheduler doesn't need to maintain state for this kind of command |
| assertFalse(impl.isWorkQueued()); |
| |
| // Busy wait for the counter |
| impl.scheduleDeferred(new ScheduledCommand() { |
| @Override |
| public void execute() { |
| if (values[0] == values[1]) { |
| finishTest(); |
| } else { |
| impl.scheduleDeferred(this); |
| } |
| } |
| }); |
| |
| delayTestFinish(TEST_DELAY); |
| } |
| |
| public void testIncrementalCommands() { |
| final SchedulerImpl impl = new SchedulerImpl(); |
| |
| final int[] values = {0, 4}; |
| final CountingCommand counter = new CountingCommand(values); |
| impl.scheduleIncremental(counter); |
| |
| // The first pass is scheduled as a deferred command |
| assertEquals(1, impl.deferredCommands.length()); |
| |
| impl.scheduleDeferred(new ScheduledCommand() { |
| @Override |
| public void execute() { |
| // After the incremental command has fired, it's moved to a new queue |
| assertNull(impl.deferredCommands); |
| assertTrue(String.valueOf(values[0]), values[0] <= values[1]); |
| |
| if (values[0] == values[1]) { |
| // Haven't yet cleared the queue, still in flushPostEventPumpCommands |
| assertNotNull(impl.incrementalCommands); |
| assertEquals(0, impl.incrementalCommands.length()); |
| finishTest(); |
| } else { |
| assertNotNull(impl.incrementalCommands); |
| assertEquals(1, impl.incrementalCommands.length()); |
| assertSame(counter, impl.incrementalCommands.get(0).getRepeating()); |
| impl.scheduleDeferred(this); |
| } |
| } |
| }); |
| |
| assertEquals(2, impl.deferredCommands.length()); |
| |
| delayTestFinish(TEST_DELAY); |
| } |
| |
| private void testQueue(final QueueTester impl) { |
| boolean[] oneShotValues = {false}; |
| final boolean[] chainedValues = {false}; |
| int[] counterValues = {0, 2}; |
| |
| impl.schedule(new ArraySetterCommand(oneShotValues)); |
| impl.schedule(new CountingCommand(counterValues)); |
| impl.schedule(new ScheduledCommand() { |
| @Override |
| public void execute() { |
| // Schedule another entry |
| impl.schedule(new ArraySetterCommand(chainedValues)); |
| } |
| }); |
| |
| assertEquals(3, impl.queue().length()); |
| |
| ScheduledCommand nullCommand = new NullCommand(); |
| impl.schedule(nullCommand); |
| assertEquals(4, impl.queue().length()); |
| assertSame(nullCommand, impl.queue().get(3).getScheduled()); |
| |
| impl.flush(); |
| |
| // Ensure the command-schedules-command case has been executed |
| assertTrue(chainedValues[0]); |
| |
| // Test that the RepeatingCommand is still scheduled |
| assertEquals(1, counterValues[0]); |
| assertEquals(1, impl.queue().length()); |
| impl.flush(); |
| |
| // Everything should be finished now |
| assertEquals(2, counterValues[0]); |
| assertTrue(oneShotValues[0]); |
| assertNull(impl.queue()); |
| } |
| } |