Skip to content

Commit

Permalink
[core] Add the function at() into the Schedules BIC.
Browse files Browse the repository at this point in the history
Signed-off-by: Stéphane Galland <galland@arakhne.org>
  • Loading branch information
gallandarakhneorg committed Oct 6, 2018
1 parent 6330876 commit efba2bd
Show file tree
Hide file tree
Showing 3 changed files with 202 additions and 5 deletions.
29 changes: 29 additions & 0 deletions main/apiplugins/io.sarl.core/src/io/sarl/core/bic.sarl
Expand Up @@ -687,6 +687,35 @@ capacity Schedules {
*/
def execute(task : AgentTask = null, procedure : (Agent) => void ) : AgentTask

/**
* Schedule a given task to be executed at the given time.
*
* <p>If the given time is passed, according to {@link Time} then the task is not executed.
*
* <p>The given procedure takes one parameter: the agent associated to the task. It is name <code>it</code> by default.
*
* <p>The given time is expressed in milliseconds according to the time scale of the SRE.
* It means that the given number of milliseconds may be not real milliseconds, depending
* on the definition of the builtin capacity {@link Time}.
*
* <p>If this function is invoked from a {@code Behavior} and there is no provided task,
* the created task will be associated to the behavior instance. It means that the task will
* be automatically canceled when the behavior instance is unregistered from the the owning agent.
*
* <p>This function does nothing if one of the following conditions evaluates to true:
* <ul>
* <li>the agent is not alive.</li>
* </ul>
*
* @param task the task that will run the given closure. If <code>null</code>, a new task is created.
* @param time the time in milliseconds at which to start the procedure execution.
* @param procedure the closure to execute.
* @return the task is given, or a new task if the procedure is schedule, or
* {@code null} if the procedure is not scheduled.
* @since 0.9
*/
def at(task : AgentTask = null, time : long, procedure : (Agent) => void) : AgentTask

}


Expand Down
Expand Up @@ -49,6 +49,7 @@
import io.sarl.core.AgentTask;
import io.sarl.core.Logging;
import io.sarl.core.Schedules;
import io.sarl.core.Time;
import io.sarl.lang.core.Agent;
import io.sarl.lang.core.AgentTrait;
import io.sarl.lang.core.Behavior;
Expand Down Expand Up @@ -79,6 +80,8 @@ public class SchedulesSkill extends BuiltinSkill implements Schedules {

private ClearableReference<Skill> skillBufferLogging;

private ClearableReference<Skill> skillBufferTime;

/** Constructor.
* @param agent the owner of this skill.
*/
Expand All @@ -97,6 +100,17 @@ protected final Logging getLoggingSkill() {
return $castSkill(Logging.class, this.skillBufferLogging);
}

/** Replies the Time skill as fast as possible.
*
* @return the skill
*/
protected final Time getTimeSkill() {
if (this.skillBufferTime == null || this.skillBufferTime.get() == null) {
this.skillBufferTime = $getSkill(Time.class);
}
return $castSkill(Time.class, this.skillBufferTime);
}

/** Replies the mutex for synchronizing on the task list.
*
* @return the mutex.
Expand Down Expand Up @@ -232,6 +246,15 @@ public AgentTask in(AgentTask task, long delay, Procedure1<? super Agent> proced
return pair.getTask();
}

@Override
public AgentTask at(AgentTask task, long time, Procedure1<? super Agent> procedure) {
final long delay = Math.round(time - getTimeSkill().getTime());
if (delay > 0.) {
return in(task, delay, procedure);
}
return task;
}

private TaskDescription preRunTask(AgentTask task, Procedure1<? super Agent> procedure) {
final TaskDescription pair;
final AgentTask rtask;
Expand Down
Expand Up @@ -26,6 +26,8 @@
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;

import static org.mockito.Mockito.*;

import java.util.Collection;
import java.util.UUID;
import java.util.concurrent.ScheduledFuture;
Expand All @@ -50,6 +52,7 @@
import org.mockito.stubbing.Answer;

import io.janusproject.kernel.bic.SchedulesSkill;
import io.janusproject.kernel.bic.TimeSkill;
import io.janusproject.services.executor.ExecutorService;
import io.janusproject.services.logging.LogService;
import io.janusproject.tests.testutils.AbstractJanusRunTest;
Expand All @@ -61,12 +64,15 @@
import io.sarl.core.Initialize;
import io.sarl.core.Lifecycle;
import io.sarl.core.Schedules;
import io.sarl.core.Time;
import io.sarl.lang.SARLVersion;
import io.sarl.lang.annotation.PerceptGuardEvaluator;
import io.sarl.lang.annotation.SarlSpecification;
import io.sarl.lang.core.Agent;
import io.sarl.lang.core.Behavior;
import io.sarl.lang.core.BuiltinCapacitiesProvider;
import io.sarl.lang.core.SREutils;
import io.sarl.lang.core.Skill;
import io.sarl.lang.core.Skill.UninstallationStage;
import io.sarl.tests.api.Nullable;

Expand All @@ -89,22 +95,72 @@ public static class StaticTests extends AbstractJanusTest {
@Nullable
private UUID agentId;

@InjectMocks
private SchedulesSkill skill;

@Mock
private ExecutorService executorService;

@Mock
private LogService logger;

private Agent agent;

@Mock
private LogService logger;
private Skill timeSkill;

@InjectMocks
private SchedulesSkill skill;
/**
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
*/
private static class TimeSkillMock extends Skill implements Time {

public TimeSkillMock(Agent agent) {
super(agent);
}

@Override
public double getTime(TimeUnit timeUnit) {
return 0;
}

@Override
public double getOSTimeFactor() {
return 1;
}

@Override
public double toOSTime(double timeValue) {
return timeValue;
}

@Override
public double fromOSTime(double timeValue) {
return timeValue;
}

@Override
public double toOSDuration(double timeDuration) {
return timeDuration;
}

@Override
public double fromOSDuration(double timeDuration) {
return timeDuration;
}

}

@Before
public void setUp() throws Exception {
this.agentId = UUID.randomUUID();
Mockito.when(this.agent.getID()).thenReturn(this.agentId);
this.agent = new Agent(UUID.randomUUID(), this.agentId);
this.agent = spy(this.agent);
this.timeSkill = new TimeSkillMock(this.agent);
this.timeSkill = spy(this.timeSkill);
SREutils.createSkillMapping(this.agent, Time.class, this.timeSkill);
this.reflect.invoke(this.skill, "setOwner", this.agent);
Mockito.when(this.executorService.schedule(ArgumentMatchers.any(Runnable.class), ArgumentMatchers.any(long.class),
ArgumentMatchers.any(TimeUnit.class))).thenAnswer(new Answer<ScheduledFuture>() {
@Override
Expand Down Expand Up @@ -235,6 +291,95 @@ public void everyAgentTaskLongProcedure1() {
assertSame(TimeUnit.MILLISECONDS, argument4.getValue());
}

@Test
public void atLongProcedure1_inTheFuture() {
Procedure1 procedure = Mockito.mock(Procedure1.class);
AgentTask task = this.skill.at(5, procedure);
assertNotNull(task);
assertSame(procedure, task.getProcedure());
ArgumentCaptor<Runnable> argument1 = ArgumentCaptor.forClass(Runnable.class);
ArgumentCaptor<Long> argument2 = ArgumentCaptor.forClass(Long.class);
ArgumentCaptor<TimeUnit> argument3 = ArgumentCaptor.forClass(TimeUnit.class);
Mockito.verify(this.executorService, new Times(1)).schedule(argument1.capture(), argument2.capture(),
argument3.capture());
assertNotNull(argument1.getValue());
assertEquals(new Long(5), argument2.getValue());
assertSame(TimeUnit.MILLISECONDS, argument3.getValue());
}

@Test
public void atLongProcedure1_now() {
Procedure1 procedure = Mockito.mock(Procedure1.class);
AgentTask task = this.skill.at(0, procedure);
assertNull(task);
ArgumentCaptor<Runnable> argument1 = ArgumentCaptor.forClass(Runnable.class);
ArgumentCaptor<Long> argument2 = ArgumentCaptor.forClass(Long.class);
ArgumentCaptor<TimeUnit> argument3 = ArgumentCaptor.forClass(TimeUnit.class);
Mockito.verify(this.executorService, never()).schedule(argument1.capture(), argument2.capture(),
argument3.capture());
}

@Test
public void atLongProcedure1_inThePast() {
Procedure1 procedure = Mockito.mock(Procedure1.class);
AgentTask task = this.skill.at(-5, procedure);
assertNull(task);
ArgumentCaptor<Runnable> argument1 = ArgumentCaptor.forClass(Runnable.class);
ArgumentCaptor<Long> argument2 = ArgumentCaptor.forClass(Long.class);
ArgumentCaptor<TimeUnit> argument3 = ArgumentCaptor.forClass(TimeUnit.class);
Mockito.verify(this.executorService, never()).schedule(argument1.capture(), argument2.capture(),
argument3.capture());
}

@Test
public void atAgentTaskLongProcedure1_inTheFuture() {
AgentTask task = Mockito.mock(AgentTask.class);
Mockito.when(task.getName()).thenReturn("thetask"); //$NON-NLS-1$
Procedure1 procedure = Mockito.mock(Procedure1.class);
AgentTask t = this.skill.at(task, 5, procedure);
assertSame(task, t);
ArgumentCaptor<Procedure1> argument0 = ArgumentCaptor.forClass(Procedure1.class);
Mockito.verify(task, new Times(1)).setProcedure(argument0.capture());
assertSame(procedure, argument0.getValue());
ArgumentCaptor<Runnable> argument1 = ArgumentCaptor.forClass(Runnable.class);
ArgumentCaptor<Long> argument2 = ArgumentCaptor.forClass(Long.class);
ArgumentCaptor<TimeUnit> argument3 = ArgumentCaptor.forClass(TimeUnit.class);
Mockito.verify(this.executorService, new Times(1)).schedule(argument1.capture(), argument2.capture(),
argument3.capture());
assertNotNull(argument1.getValue());
assertEquals(new Long(5), argument2.getValue());
assertSame(TimeUnit.MILLISECONDS, argument3.getValue());
}

@Test
public void atAgentTaskLongProcedure1_now() {
AgentTask task = Mockito.mock(AgentTask.class);
Mockito.when(task.getName()).thenReturn("thetask"); //$NON-NLS-1$
Procedure1 procedure = Mockito.mock(Procedure1.class);
AgentTask t = this.skill.at(task, 0, procedure);
assertSame(task, t);
ArgumentCaptor<Runnable> argument1 = ArgumentCaptor.forClass(Runnable.class);
ArgumentCaptor<Long> argument2 = ArgumentCaptor.forClass(Long.class);
ArgumentCaptor<TimeUnit> argument3 = ArgumentCaptor.forClass(TimeUnit.class);
Mockito.verify(this.executorService, never()).schedule(argument1.capture(), argument2.capture(),
argument3.capture());
}

@Test
public void atAgentTaskLongProcedure1_inThePast() {
AgentTask task = Mockito.mock(AgentTask.class);
Mockito.when(task.getName()).thenReturn("thetask"); //$NON-NLS-1$
Procedure1 procedure = Mockito.mock(Procedure1.class);
AgentTask t = this.skill.at(task, -5, procedure);
assertSame(task, t);
assertSame(task, t);
ArgumentCaptor<Runnable> argument1 = ArgumentCaptor.forClass(Runnable.class);
ArgumentCaptor<Long> argument2 = ArgumentCaptor.forClass(Long.class);
ArgumentCaptor<TimeUnit> argument3 = ArgumentCaptor.forClass(TimeUnit.class);
Mockito.verify(this.executorService, never()).schedule(argument1.capture(), argument2.capture(),
argument3.capture());
}

@Test
public void uninstall() throws Exception {
Procedure1 procedure1 = Mockito.mock(Procedure1.class);
Expand Down

0 comments on commit efba2bd

Please sign in to comment.