diff --git a/docs/io.sarl.docs.suite/src/test/java/io/sarl/docs/reference/BIC.spec b/docs/io.sarl.docs.suite/src/test/java/io/sarl/docs/reference/BIC.spec index b802a219ed..7d946c062e 100644 --- a/docs/io.sarl.docs.suite/src/test/java/io/sarl/docs/reference/BIC.spec +++ b/docs/io.sarl.docs.suite/src/test/java/io/sarl/docs/reference/BIC.spec @@ -1084,7 +1084,7 @@ describe "Built-in Capacity Reference" { }".parseSuccessfully } - /* For running a periodic task, the following functions are + /* For running a periodic task with a fixed starting rate, the following functions are * provided: * * def every(period : long, @@ -1130,7 +1130,7 @@ describe "Built-in Capacity Reference" { * * @filter(.*) */ - fact "Launching a Periodic Task"{ + fact "Launching a Periodic Task at a Fixed Rate"{ "GeneralSyntaxReferenceSpec.html" should beAccessibleFrom this // " package io.sarl.docs.reference.bic @@ -1153,6 +1153,73 @@ describe "Built-in Capacity Reference" { }".parseSuccessfully } + /* For running a periodic task with a fixed duration between the runs, the following functions are + * provided: + * + * def atFixedDelay(period : long, + * procedure : (Agent) => void) : AgentTask + * def atFixedDelay(period : AgentTask, + * delay : long, + * procedure : (Agent) => void) : AgentTask + * + * + *

The first function submits the given procedure (a lambda expression as defined in + * the [General Syntax Reference](GeneralSyntaxReferenceSpec.html)) to + * an executor provided by the runtime platform. The execution of the procedure + * will be launched periodically with a duration between the runs of the given number of milliseconds. + * This function replies the agent task for controlling its execution. + * + *

The second function behaves in a similar way as the first, except that it + * accepts an agent task as parameter. This task will attach to the given + * procedure. The replied task is the same as the task given as parameter. + * + *

The `atFixedDelay` function has not the same issue ass the `every` function + * regarding the possibility to have several runs in parallel. + * The `atFixedDelay` ensures that only one run of the procedure will be executed at a giveen time. + * + *

For example, the following code may be illustrated by the table below. + * + * + * atFixedDelay(500) [ sleep(2000) ] + * + * + * + * + * + * 5000 + * + * + * + * + * + * + *
t=050010001500200025003000350040004500550060006500
AXXXX
BXXXX
CXXXX
+ * + * @filter(.*) + */ + fact "Launching a Periodic Task with a Fixed Delay between the Runs"{ + "GeneralSyntaxReferenceSpec.html" should beAccessibleFrom this + // + " package io.sarl.docs.reference.bic + import io.sarl.core.Logging + import io.sarl.core.Schedules + import io.sarl.core.AgentTask + import io.sarl.lang.core.Agent + agent A { + uses Schedules, Logging + def myaction { + var t1 : AgentTask + var t2 : AgentTask + t1 = atFixedDelay(1000) [ a : Agent | + println(a) + ] + t1 = t2.atFixedDelay(1000) [ a : Agent | + println(a) + ] + } + }".parseSuccessfully + } + /* It may be useful to cancel a running task, e.g. a * periodic task. The `Schedules` capacity * provides two functions for stopping the execution diff --git a/docs/io.sarl.docs.suite/src/test/java/io/sarl/docs/tutorials/CreateSREWithTinyMAS.spec b/docs/io.sarl.docs.suite/src/test/java/io/sarl/docs/tutorials/CreateSREWithTinyMAS.spec index 792f725fb2..6ccce28bbd 100644 --- a/docs/io.sarl.docs.suite/src/test/java/io/sarl/docs/tutorials/CreateSREWithTinyMAS.spec +++ b/docs/io.sarl.docs.suite/src/test/java/io/sarl/docs/tutorials/CreateSREWithTinyMAS.spec @@ -2192,6 +2192,9 @@ describe "Creating a SARL Run-time Environment for the tinyMAS platform"{ * the `in` function, except that the `period` field of the `Task` is set * with the period duration, which is given as parameter. * + *

The `atFixedDelay` function delegates to the `every` function because the task running + * algorithm implies that these two types of execution approach will be the same on tinyMAS. + * * @filter(.* = '''|'''|.parseSuccessfully.*) */ fact "Scheduling a periodic agent task" { @@ -2210,6 +2213,10 @@ describe "Creating a SARL Run-time Environment for the tinyMAS platform"{ scheduleTask(time, theTask) return theTask } + + def atFixedDelay(task : AgentTask = null, delay : long, procedure : (io.sarl.lang.core.Agent) => void) : AgentTask { + return task.every(delay, procedure) + } '''.parseSuccessfully( ''' package io.sarl.docs.tutorials.tinyMASSRE diff --git a/eclipse-sarl/plugins/io.sarl.core/src/io/sarl/core/bic.sarl b/eclipse-sarl/plugins/io.sarl.core/src/io/sarl/core/bic.sarl index b35f12b89f..989bb6e31d 100644 --- a/eclipse-sarl/plugins/io.sarl.core/src/io/sarl/core/bic.sarl +++ b/eclipse-sarl/plugins/io.sarl.core/src/io/sarl/core/bic.sarl @@ -353,9 +353,10 @@ capacity Schedules { /** * Schedule a periodic execution of the given task. - *

- * If the duration of the task is greater to the given period length, then - * multiple task's instances will be run in parallel. + * + *

If the duration of the task is greater to the given period length, then + * multiple task's instances will be run in parallel, in opposite to the + * {@code atFixedDelay()} function. * For example, consider the following code: *


 	 * every(500) [ sleep(2000) ]
@@ -371,6 +372,8 @@ capacity Schedules {
 	 *                             [-E-------------------------]
 	 *                                    [-F-------------------------]
 	 * 
+ * For executing a task with a fixed delay between the runs, and not at a fixed rate, + * you should use the {@code atFixedDelay()} function. * *

The given procedure takes one parameter: the agent associated to the task. It is name it by default. * @@ -381,6 +384,41 @@ capacity Schedules { */ def every(task : AgentTask = null, period : long, procedure : (Agent) => void ) : AgentTask + /** + * Schedule a single-execution task. + * + *

If the duration of the task is greater to the given delay length, then + * no multiple task's instance are run in parallel, in opposite to the + * {@code every()} function. + * For example, consider the following code: + *


+	 * atFixedDelay(500) [ sleep(2000) ]
+	 * 
+ * At a given time, 3 instances (A, B, C) of the task are run in sequence, and + * each run is separated by 500 milliseconds: + *

+	 * t=0   0500   1000   1500   2000   2500   3000   3500   4000   4500   5000
+	 *   |    |      |      |      |      |      |      |      |      |      |
+	 *   [-A-----------------------]
+	 *                                    [-B-------------------------]
+	 *                                                                       [-C-------------------------]
+	 * 
+ * For executing a task with a fixed rate, and not with a fixed delay between the task runs, + * you should use the {@code every()} function. + * + *

The given procedure takes one parameter: the agent associated to the task. It is name it by default. + * + *

It is recommended that the SRAL run-time environment, which is providing the implementation + * of this function to provide an efficient implementation in the case the argument + * {@code delay} is equal to zero. Indeed, if the {@code delay} is equal to zero, the task + * should be run in an infinite loop until it is canceled, or the owning agent is killed. + * + * @param task the task to associate to the procedure. If null a new task is created. + * @param procedure the procedure to launch. The parameter of the procedure is the agent. + * @return the given task. + * @since 0.5 + */ + def atFixedDelay(task : AgentTask = null, delay : long, procedure : (Agent) => void ) : AgentTask } diff --git a/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/bic/Messages.java b/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/bic/Messages.java index e5fbbf3ddc..adb22accf8 100644 --- a/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/bic/Messages.java +++ b/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/bic/Messages.java @@ -42,6 +42,7 @@ public class Messages extends NLS { public static String SchedulesSkill_0; public static String SchedulesSkill_1; public static String SchedulesSkill_2; + public static String SchedulesSkill_3; static { // initialize resource bundle NLS.initializeMessages(BUNDLE_NAME, Messages.class); diff --git a/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/bic/SchedulesSkill.java b/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/bic/SchedulesSkill.java index 60b6d88dfb..c38c110b58 100644 --- a/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/bic/SchedulesSkill.java +++ b/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/bic/SchedulesSkill.java @@ -22,16 +22,21 @@ package io.janusproject.kernel.bic; import java.lang.ref.WeakReference; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.UUID; +import java.util.concurrent.Future; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.LogRecord; import com.google.common.base.MoreObjects; +import com.google.common.base.Strings; import com.google.inject.Inject; import io.janusproject.services.executor.ExecutorService; import io.janusproject.services.executor.JanusScheduledFutureTask; @@ -63,7 +68,7 @@ public class SchedulesSkill extends BuiltinSkill implements Schedules { private final Map tasks = new HashMap<>(); - private final Map> futures = new HashMap<>(); + private final Map> futures = new HashMap<>(); /** * @param agent - the owner of this skill. @@ -100,7 +105,7 @@ private synchronized void finishTask(String name) { * * @return the names of the active tasks. */ - synchronized Collection getActiveTasks() { + public synchronized Collection getActiveTasks() { return new ArrayList<>(this.tasks.keySet()); } @@ -109,14 +114,24 @@ synchronized Collection getActiveTasks() { * * @return the names of the active futures. */ - synchronized Collection> getActiveFutures() { + synchronized Collection> getActiveFutures() { return new ArrayList<>(this.futures.values()); } + /** + * Replies the active future for the task with the given name. + * + * @param name the name of the task. + * @return the active future of the task. + */ + synchronized Future getActiveFuture(String name) { + return this.futures.get(name); + } + @Override protected synchronized void uninstall() { - ScheduledFuture future; - for (final Entry> futureDescription : this.futures.entrySet()) { + Future future; + for (final Entry> futureDescription : this.futures.entrySet()) { future = futureDescription.getValue(); if ((future instanceof JanusScheduledFutureTask) && ((JanusScheduledFutureTask) future).isCurrentThread()) { // Ignore the cancelation of the future. @@ -139,7 +154,7 @@ public AgentTask in(long delay, Procedure1 procedure) { @Override public synchronized AgentTask in(AgentTask task, long delay, Procedure1 procedure) { - final AgentTask rtask = task == null ? task("task-" + UUID.randomUUID()) : task; //$NON-NLS-1$ + final AgentTask rtask = task == null ? task(null) : task; rtask.setProcedure(procedure); final ScheduledFuture sf = this.executorService.schedule(new AgentRunnableTask(rtask, false), delay, TimeUnit.MILLISECONDS); this.futures.put(rtask.getName(), sf); @@ -148,19 +163,13 @@ public synchronized AgentTask in(AgentTask task, long delay, Procedure1() { - - @Override - public Boolean apply(Agent arg0) { - return Boolean.TRUE; - } - }); - this.tasks.put(name, t); + t.setName(realName); + this.tasks.put(realName, t); return t; } @@ -173,9 +182,10 @@ public final boolean cancel(AgentTask task) { public synchronized boolean cancel(AgentTask task, boolean mayInterruptIfRunning) { if (task != null) { final String name = task.getName(); - final ScheduledFuture future = this.futures.get(name); + final Future future = this.futures.get(name); if (future != null && !future.isDone() && !future.isCancelled() && future.cancel(mayInterruptIfRunning)) { finishTask(name); + return true; } } return false; @@ -188,7 +198,7 @@ public AgentTask every(long period, Procedure1 procedure) { @Override public synchronized AgentTask every(AgentTask task, long period, Procedure1 procedure) { - final AgentTask rtask = task == null ? task("task-" + UUID.randomUUID()) : task; //$NON-NLS-1$ + final AgentTask rtask = task == null ? task(null) : task; rtask.setProcedure(procedure); final ScheduledFuture sf = this.executorService.scheduleAtFixedRate(new AgentRunnableTask(rtask, true), 0, period, TimeUnit.MILLISECONDS); @@ -196,6 +206,32 @@ public synchronized AgentTask every(AgentTask task, long period, Procedure1 procedure) { + return atFixedDelay(Schedules.$DEFAULT_VALUE$ATFIXEDDELAY_0, delay, procedure); + } + + @Override + public synchronized AgentTask atFixedDelay(AgentTask task, long delay, Procedure1 procedure) { + final AgentTask rtask = task == null ? task(null) : task; + rtask.setProcedure(procedure); + final Future future; + if (delay <= 0) { + future = this.executorService.submit(new AgentInfiniteLoopTask(rtask)); + } else { + future = this.executorService.scheduleWithFixedDelay( + new AgentRunnableTask(rtask, true), + 0, delay, TimeUnit.MILLISECONDS); + } + this.futures.put(rtask.getName(), future); + return rtask; + } + + @Override + public AgentTask execute(Procedure1 procedure) { + return execute(Schedules.$DEFAULT_VALUE$EXECUTE_0, procedure); + } + /** * Implementation of an agent task. * @@ -221,13 +257,100 @@ public void run() { if (task == null) { throw new RuntimeException(Messages.SchedulesSkill_2); } + boolean hasError = false; + try { + final Agent owner = getOwner(); + final Function1 guard = task.getGuard(); + if (guard == null || guard.apply(owner).booleanValue()) { + final Procedure1 procedure = task.getProcedure(); + if (procedure != null) { + procedure.apply(owner); + } + } + } catch (Throwable ex) { + final LogRecord record = new LogRecord(Level.SEVERE, + MessageFormat.format(Messages.SchedulesSkill_3, toString(), ex.getLocalizedMessage())); + record.setThrown(ex); + SchedulesSkill.this.logger.log(record); + hasError = true; + } finally { + if (hasError || !this.isPeriodic) { + finishTask(task.getName()); + } + } + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this).add("name", this.agentTaskRef.get().getName()) //$NON-NLS-1$ + .add("agent", getOwner().getID()).toString(); //$NON-NLS-1$ + } + + } + + /** + * Implementation of an agent infinite loop task. + * + * @author $Author: srodriguez$ + * @version $Name$ $Revision$ $Date$ + * @mavengroupid $GroupId$ + * @mavenartifactid $ArtifactId$ + */ + @SuppressWarnings("synthetic-access") + private class AgentInfiniteLoopTask implements Runnable { + private WeakReference agentTaskRef; + + AgentInfiniteLoopTask(AgentTask task) { + this.agentTaskRef = new WeakReference<>(task); + } + + private boolean canRun() { + final AgentTask task = this.agentTaskRef.get(); + if (task != null) { + final Future future = getActiveFuture(task.getName()); + return future != null && !future.isDone() && !future.isCancelled(); + } + return false; + } + + private Function1 getGuard() { + final AgentTask task = this.agentTaskRef.get(); + if (task != null) { + return task.getGuard(); + } + return null; + } + + private Procedure1 getProcedure() { + final AgentTask task = this.agentTaskRef.get(); + if (task != null) { + return task.getProcedure(); + } + return null; + } + + @Override + public void run() { try { final Agent owner = getOwner(); - if (task.getGuard().apply(owner).booleanValue()) { - task.getProcedure().apply(owner); + while (canRun()) { + final Function1 guard = getGuard(); + if (guard == null || guard.apply(owner).booleanValue()) { + final Procedure1 procedure = getProcedure(); + if (procedure != null) { + procedure.apply(owner); + } + } + Thread.yield(); } + } catch (Throwable ex) { + final LogRecord record = new LogRecord(Level.SEVERE, + MessageFormat.format(Messages.SchedulesSkill_3, toString(), ex.getLocalizedMessage())); + record.setThrown(ex); + SchedulesSkill.this.logger.log(record); } finally { - if (!this.isPeriodic) { + final AgentTask task = this.agentTaskRef.get(); + if (task != null) { finishTask(task.getName()); } } @@ -240,4 +363,5 @@ public String toString() { } } + } diff --git a/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/bic/messages.properties b/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/bic/messages.properties index a3e8d53bef..31a9c61299 100644 --- a/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/bic/messages.properties +++ b/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/bic/messages.properties @@ -7,3 +7,4 @@ LoggingSkill_0=AGENT-{0} SchedulesSkill_0=The cancellation of the task '{0}' is skipped: {1}. SchedulesSkill_1=The task '{0}' is cancelled: {1}. SchedulesSkill_2=Agent task is null. +SchedulesSkill_3=Error in agent's task {0}: {1} diff --git a/sre/io.janusproject/io.janusproject.tests/src/io/janusproject/tests/kernel/bic/SchedulesSkillTest.java b/sre/io.janusproject/io.janusproject.tests/src/io/janusproject/tests/kernel/bic/SchedulesSkillTest.java index ef01e308e0..7f7cd9ce40 100644 --- a/sre/io.janusproject/io.janusproject.tests/src/io/janusproject/tests/kernel/bic/SchedulesSkillTest.java +++ b/sre/io.janusproject/io.janusproject.tests/src/io/janusproject/tests/kernel/bic/SchedulesSkillTest.java @@ -19,7 +19,7 @@ */ package io.janusproject.tests.kernel.bic; -import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.*; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; @@ -29,14 +29,15 @@ import java.util.UUID; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; -import io.janusproject.kernel.bic.SchedulesSkill; -import io.janusproject.services.executor.ExecutorService; -import io.janusproject.services.logging.LogService; -import io.janusproject.tests.testutils.AbstractJanusTest; +import org.eclipse.xtext.util.Strings; import org.eclipse.xtext.xbase.lib.Procedures.Procedure1; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; import org.mockito.ArgumentCaptor; import org.mockito.ArgumentMatchers; import org.mockito.InjectMocks; @@ -46,8 +47,18 @@ import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; +import io.janusproject.kernel.bic.SchedulesSkill; +import io.janusproject.services.executor.ExecutorService; +import io.janusproject.services.logging.LogService; +import io.janusproject.tests.bugs.Bug84.KilledInInitAgent; +import io.janusproject.tests.testutils.AbstractJanusRunTest; +import io.janusproject.tests.testutils.AbstractJanusTest; import io.sarl.core.AgentTask; +import io.sarl.core.Schedules; +import io.sarl.lang.SARLVersion; +import io.sarl.lang.annotation.SarlSpecification; import io.sarl.lang.core.Agent; +import io.sarl.lang.core.BuiltinCapacitiesProvider; import io.sarl.tests.api.Nullable; /** @@ -57,215 +68,563 @@ * @mavenartifactid $ArtifactId$ */ @SuppressWarnings("all") -public class SchedulesSkillTest extends AbstractJanusTest { - - @Nullable - private UUID agentId; - - @Mock - private ExecutorService executorService; - - @Mock - private Agent agent; - - @Mock - private LogService logger; - - @InjectMocks - private SchedulesSkill skill; - - @Before - public void setUp() throws Exception { - this.agentId = UUID.randomUUID(); - Mockito.when(this.agent.getID()).thenReturn(this.agentId); - Mockito.when(this.executorService.schedule(ArgumentMatchers.any(Runnable.class), ArgumentMatchers.any(long.class), - ArgumentMatchers.any(TimeUnit.class))).thenAnswer(new Answer() { - @Override - public ScheduledFuture answer(InvocationOnMock invocation) throws Throwable { - ScheduledFuture f = Mockito.mock(ScheduledFuture.class); - Mockito.when(f.isDone()).thenReturn(false); - Mockito.when(f.isCancelled()).thenReturn(false); - Mockito.when(f.cancel(ArgumentMatchers.anyBoolean())).thenReturn(true); - return f; +@RunWith(Suite.class) +@SuiteClasses({ + SchedulesSkillTest.SchedulesAPITest.class, + SchedulesSkillTest.SchedulesRunTest.class +}) +public class SchedulesSkillTest { + + public static class SchedulesAPITest extends AbstractJanusTest { + + @Nullable + private UUID agentId; + + @Mock + private ExecutorService executorService; + + @Mock + private Agent agent; + + @Mock + private LogService logger; + + @InjectMocks + private SchedulesSkill skill; + + @Before + public void setUp() throws Exception { + this.agentId = UUID.randomUUID(); + Mockito.when(this.agent.getID()).thenReturn(this.agentId); + Mockito.when(this.executorService.schedule(ArgumentMatchers.any(Runnable.class), ArgumentMatchers.any(long.class), + ArgumentMatchers.any(TimeUnit.class))).thenAnswer(new Answer() { + @Override + public ScheduledFuture answer(InvocationOnMock invocation) throws Throwable { + ScheduledFuture f = Mockito.mock(ScheduledFuture.class); + Mockito.when(f.isDone()).thenReturn(false); + Mockito.when(f.isCancelled()).thenReturn(false); + Mockito.when(f.cancel(ArgumentMatchers.anyBoolean())).thenReturn(true); + return f; + } + }); + Mockito.when(this.executorService.scheduleAtFixedRate(ArgumentMatchers.any(Runnable.class), ArgumentMatchers.any(long.class), + ArgumentMatchers.any(long.class), ArgumentMatchers.any(TimeUnit.class))).thenAnswer(new Answer() { + @Override + public ScheduledFuture answer(InvocationOnMock invocation) throws Throwable { + ScheduledFuture f = Mockito.mock(ScheduledFuture.class); + Mockito.when(f.isDone()).thenReturn(false); + Mockito.when(f.isCancelled()).thenReturn(false); + Mockito.when(f.cancel(ArgumentMatchers.anyBoolean())).thenReturn(true); + return f; + } + }); + } + + @Test + public void task() { + AgentTask task = this.skill.task("thename"); //$NON-NLS-1$ + assertNotNull(task); + assertNull(task.getGuard()); + assertNull(task.getProcedure()); + assertEquals("thename", task.getName()); //$NON-NLS-1$ + // + AgentTask task2 = this.skill.task("thename"); //$NON-NLS-1$ + assertSame(task, task2); + // + AgentTask task3 = this.skill.task("thename2"); //$NON-NLS-1$ + assertNotSame(task, task3); + // + AgentTask task4 = this.skill.task(null); + assertNotNull(task4); + assertNull(task4.getGuard()); + assertNull(task4.getProcedure()); + assertFalse(Strings.isEmpty(task4.getName())); + // + AgentTask task5 = this.skill.task(""); + assertNotNull(task5); + assertNull(task5.getGuard()); + assertNull(task5.getProcedure()); + assertFalse(Strings.isEmpty(task5.getName())); + } + + @Test + public void inLongProcedure1() { + Procedure1 procedure = Mockito.mock(Procedure1.class); + AgentTask task = this.skill.in(5, procedure); + assertNotNull(task); + assertSame(procedure, task.getProcedure()); + ArgumentCaptor argument1 = ArgumentCaptor.forClass(Runnable.class); + ArgumentCaptor argument2 = ArgumentCaptor.forClass(Long.class); + ArgumentCaptor 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 inAgentTaskLongProcedure1() { + 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.in(task, 5, procedure); + assertSame(task, t); + ArgumentCaptor argument0 = ArgumentCaptor.forClass(Procedure1.class); + Mockito.verify(task, new Times(1)).setProcedure(argument0.capture()); + assertSame(procedure, argument0.getValue()); + ArgumentCaptor argument1 = ArgumentCaptor.forClass(Runnable.class); + ArgumentCaptor argument2 = ArgumentCaptor.forClass(Long.class); + ArgumentCaptor 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 everyLongProcedure1() { + Procedure1 procedure = Mockito.mock(Procedure1.class); + AgentTask task = this.skill.every(5, procedure); + assertNotNull(task); + assertSame(procedure, task.getProcedure()); + ArgumentCaptor argument1 = ArgumentCaptor.forClass(Runnable.class); + ArgumentCaptor argument2 = ArgumentCaptor.forClass(Long.class); + ArgumentCaptor argument3 = ArgumentCaptor.forClass(Long.class); + ArgumentCaptor argument4 = ArgumentCaptor.forClass(TimeUnit.class); + Mockito.verify(this.executorService, new Times(1)).scheduleAtFixedRate(argument1.capture(), argument2.capture(), + argument3.capture(), argument4.capture()); + assertNotNull(argument1.getValue()); + assertEquals(new Long(0), argument2.getValue()); + assertEquals(new Long(5), argument3.getValue()); + assertSame(TimeUnit.MILLISECONDS, argument4.getValue()); + } + + @Test + public void everyAgentTaskLongProcedure1() { + 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.every(task, 5, procedure); + assertSame(task, t); + ArgumentCaptor argument0 = ArgumentCaptor.forClass(Procedure1.class); + Mockito.verify(task, new Times(1)).setProcedure(argument0.capture()); + assertSame(procedure, argument0.getValue()); + ArgumentCaptor argument1 = ArgumentCaptor.forClass(Runnable.class); + ArgumentCaptor argument2 = ArgumentCaptor.forClass(Long.class); + ArgumentCaptor argument3 = ArgumentCaptor.forClass(Long.class); + ArgumentCaptor argument4 = ArgumentCaptor.forClass(TimeUnit.class); + Mockito.verify(this.executorService, new Times(1)).scheduleAtFixedRate(argument1.capture(), argument2.capture(), + argument3.capture(), argument4.capture()); + assertNotNull(argument1.getValue()); + assertEquals(new Long(0), argument2.getValue()); + assertEquals(new Long(5), argument3.getValue()); + assertSame(TimeUnit.MILLISECONDS, argument4.getValue()); + } + + @Test + public void uninstall() throws Exception { + Procedure1 procedure1 = Mockito.mock(Procedure1.class); + this.skill.every(5, procedure1); + Procedure1 procedure2 = Mockito.mock(Procedure1.class); + this.skill.in(5, procedure2); + Collection> futures = (Collection>) this.reflect.invoke(this.skill, "getActiveFutures"); + assertEquals(2, futures.size()); + // + this.reflect.invoke(this.skill, "uninstall"); + // + Collection activeTasks = (Collection) this.reflect.invoke(this.skill, "getActiveTasks"); + assertTrue(activeTasks.isEmpty()); + for (ScheduledFuture f : futures) { + Mockito.verify(f, new Times(1)).cancel(ArgumentMatchers.anyBoolean()); + } + } + + @Test + public void cancelAgentTask() throws Exception { + Procedure1 procedure1 = Mockito.mock(Procedure1.class); + AgentTask t1 = this.skill.every(5, procedure1); + Procedure1 procedure2 = Mockito.mock(Procedure1.class); + AgentTask t2 = this.skill.in(5, procedure2); + Collection> futures = (Collection>) this.reflect.invoke(this.skill, "getActiveFutures"); + assertEquals(2, futures.size()); + // + this.skill.cancel(t2); + this.skill.cancel(t1); + // + Collection activeTasks = (Collection) this.reflect.invoke(this.skill, "getActiveTasks"); + assertTrue(activeTasks.isEmpty()); + for (ScheduledFuture f : futures) { + Mockito.verify(f, new Times(1)).cancel(ArgumentMatchers.anyBoolean()); + } + } + + @Test + public void cancelAgentTaskBoolean_true() throws Exception { + Procedure1 procedure1 = Mockito.mock(Procedure1.class); + AgentTask t1 = this.skill.every(5, procedure1); + Procedure1 procedure2 = Mockito.mock(Procedure1.class); + AgentTask t2 = this.skill.in(5, procedure2); + Collection> futures = (Collection>) this.reflect.invoke(this.skill, "getActiveFutures"); + assertEquals(2, futures.size()); + // + this.skill.cancel(t2, true); + this.skill.cancel(t1, true); + // + Collection activeTasks = (Collection) this.reflect.invoke(this.skill, "getActiveTasks"); + assertTrue(activeTasks.isEmpty()); + for (ScheduledFuture f : futures) { + Mockito.verify(f, new Times(1)).cancel(ArgumentMatchers.anyBoolean()); + } + } + + @Test + public void cancelAgentTaskBoolean_false() throws Exception { + Procedure1 procedure1 = Mockito.mock(Procedure1.class); + AgentTask t1 = this.skill.every(5, procedure1); + Procedure1 procedure2 = Mockito.mock(Procedure1.class); + AgentTask t2 = this.skill.in(5, procedure2); + Collection> futures = (Collection>) this.reflect.invoke(this.skill, "getActiveFutures"); + assertEquals(2, futures.size()); + // + this.skill.cancel(t2, false); + this.skill.cancel(t1, false); + // + Collection activeTasks = (Collection) this.reflect.invoke(this.skill, "getActiveTasks"); + assertTrue(activeTasks.isEmpty()); + for (ScheduledFuture f : futures) { + Mockito.verify(f, new Times(1)).cancel(ArgumentMatchers.anyBoolean()); + } + } + + @Test + public void atFixedDelayLongProcedure1() { + Procedure1 procedure = Mockito.mock(Procedure1.class); + AgentTask task = this.skill.atFixedDelay(500, procedure); + assertNotNull(task); + assertSame(procedure, task.getProcedure()); + ArgumentCaptor argument1 = ArgumentCaptor.forClass(Runnable.class); + ArgumentCaptor argument2 = ArgumentCaptor.forClass(Long.class); + ArgumentCaptor argument3 = ArgumentCaptor.forClass(Long.class); + ArgumentCaptor argument4 = ArgumentCaptor.forClass(TimeUnit.class); + Mockito.verify(this.executorService, new Times(1)).scheduleWithFixedDelay(argument1.capture(), argument2.capture(), + argument3.capture(), argument4.capture()); + assertNotNull(argument1.getValue()); + assertEquals(new Long(0), argument2.getValue()); + assertEquals(new Long(500), argument3.getValue()); + assertSame(TimeUnit.MILLISECONDS, argument4.getValue()); + } + + @Test + public void atFixedDelayAgentTaskLongProcedure1() { + 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.atFixedDelay(task, 500, procedure); + assertSame(task, t); + ArgumentCaptor argument0 = ArgumentCaptor.forClass(Procedure1.class); + Mockito.verify(task, new Times(1)).setProcedure(argument0.capture()); + assertSame(procedure, argument0.getValue()); + ArgumentCaptor argument1 = ArgumentCaptor.forClass(Runnable.class); + ArgumentCaptor argument2 = ArgumentCaptor.forClass(Long.class); + ArgumentCaptor argument3 = ArgumentCaptor.forClass(Long.class); + ArgumentCaptor argument4 = ArgumentCaptor.forClass(TimeUnit.class); + Mockito.verify(this.executorService, new Times(1)).scheduleWithFixedDelay(argument1.capture(), argument2.capture(), + argument3.capture(), argument4.capture()); + assertNotNull(argument1.getValue()); + assertEquals(new Long(0), argument2.getValue()); + assertEquals(new Long(500), argument3.getValue()); + assertSame(TimeUnit.MILLISECONDS, argument4.getValue()); + } + + @Test + public void atFixedDelayLongProcedure1_zeroDelay() { + Procedure1 procedure = Mockito.mock(Procedure1.class); + AgentTask task = this.skill.atFixedDelay(0, procedure); + assertNotNull(task); + assertSame(procedure, task.getProcedure()); + ArgumentCaptor argument1 = ArgumentCaptor.forClass(Runnable.class); + Mockito.verify(this.executorService, new Times(1)).submit(argument1.capture()); + Runnable runnable = argument1.getValue(); + assertNotNull(runnable); + assertEquals("io.janusproject.kernel.bic.SchedulesSkill$AgentInfiniteLoopTask", runnable.getClass().getName()); + } + + @Test + public void atFixedDelayAgentTaskLongProcedure1_zeroDelay() { + 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.atFixedDelay(task, 0, procedure); + assertSame(task, t); + ArgumentCaptor argument0 = ArgumentCaptor.forClass(Procedure1.class); + Mockito.verify(task, new Times(1)).setProcedure(argument0.capture()); + assertSame(procedure, argument0.getValue()); + ArgumentCaptor argument1 = ArgumentCaptor.forClass(Runnable.class); + Mockito.verify(this.executorService, new Times(1)).submit(argument1.capture()); + Runnable runnable = argument1.getValue(); + assertNotNull(runnable); + assertEquals("io.janusproject.kernel.bic.SchedulesSkill$AgentInfiniteLoopTask", runnable.getClass().getName()); + } + + + } + + public static class SchedulesRunTest extends AbstractJanusRunTest { + + @Test + public void in() throws Exception { + runJanus(SchedulesRunTestAgent0.class, false); + assertEquals(1, getNumberOfResults()); + assertEquals(Boolean.TRUE, getResult(Boolean.class, 0)); + } + + /** + * @author $Author: sgalland$ + * @version $FullVersion$ + * @mavengroupid $GroupId$ + * @mavenartifactid $ArtifactId$ + */ + @SarlSpecification(SARLVersion.SPECIFICATION_RELEASE_VERSION_STRING) + public static class SchedulesRunTestAgent0 extends TestingAgent { + + public SchedulesRunTestAgent0(BuiltinCapacitiesProvider provider, UUID parentID, UUID agentID) { + super(provider, parentID, agentID); + } + + @Override + protected boolean runAgentTest() { + getSkill(Schedules.class).in(500, (it) -> { + addResult(Boolean.TRUE); + forceKillMe(); + }); + return false; + } + + } + + @Test + public void every() throws Exception { + runJanus(SchedulesRunTestAgent1.class, false); + assertEquals(2, getNumberOfResults()); + assertEquals(0, getResult(Integer.class, 0)); + assertEquals(1, getResult(Integer.class, 1)); + } + + /** + * @author $Author: sgalland$ + * @version $FullVersion$ + * @mavengroupid $GroupId$ + * @mavenartifactid $ArtifactId$ + */ + @SarlSpecification(SARLVersion.SPECIFICATION_RELEASE_VERSION_STRING) + public static class SchedulesRunTestAgent1 extends TestingAgent { + + private final AtomicInteger index = new AtomicInteger(); + + public SchedulesRunTestAgent1(BuiltinCapacitiesProvider provider, UUID parentID, UUID agentID) { + super(provider, parentID, agentID); + } + + @Override + protected boolean runAgentTest() { + getSkill(Schedules.class).every(500, (it) -> { + addResult(this.index.getAndIncrement()); + if (this.index.get() >= 2) { + forceKillMe(); } }); - Mockito.when(this.executorService.scheduleAtFixedRate(ArgumentMatchers.any(Runnable.class), ArgumentMatchers.any(long.class), - ArgumentMatchers.any(long.class), ArgumentMatchers.any(TimeUnit.class))).thenAnswer(new Answer() { - @Override - public ScheduledFuture answer(InvocationOnMock invocation) throws Throwable { - ScheduledFuture f = Mockito.mock(ScheduledFuture.class); - Mockito.when(f.isDone()).thenReturn(false); - Mockito.when(f.isCancelled()).thenReturn(false); - Mockito.when(f.cancel(ArgumentMatchers.anyBoolean())).thenReturn(true); - return f; + return false; + } + + } + + @Test + public void atFixedDelay() throws Exception { + runJanus(SchedulesRunTestAgent2.class, false); + assertEquals(2, getNumberOfResults()); + assertEquals(0, getResult(Integer.class, 0)); + assertEquals(1, getResult(Integer.class, 1)); + } + + /** + * @author $Author: sgalland$ + * @version $FullVersion$ + * @mavengroupid $GroupId$ + * @mavenartifactid $ArtifactId$ + */ + @SarlSpecification(SARLVersion.SPECIFICATION_RELEASE_VERSION_STRING) + public static class SchedulesRunTestAgent2 extends TestingAgent { + + private final AtomicInteger index = new AtomicInteger(); + + public SchedulesRunTestAgent2(BuiltinCapacitiesProvider provider, UUID parentID, UUID agentID) { + super(provider, parentID, agentID); + } + + @Override + protected boolean runAgentTest() { + getSkill(Schedules.class).atFixedDelay(500, (it) -> { + addResult(this.index.getAndIncrement()); + if (this.index.get() >= 2) { + forceKillMe(); } }); - } + return false; + } - @Test - public void task() { - AgentTask task = this.skill.task("thename"); //$NON-NLS-1$ - assertNotNull(task); - assertNotNull(task.getGuard()); - assertNull(task.getProcedure()); - assertEquals("thename", task.getName()); //$NON-NLS-1$ - // - AgentTask task2 = this.skill.task("thename"); //$NON-NLS-1$ - assertSame(task, task2); - // - AgentTask task3 = this.skill.task("thename2"); //$NON-NLS-1$ - assertNotSame(task, task3); - } + } - @Test - public void inLongProcedure1() { - Procedure1 procedure = Mockito.mock(Procedure1.class); - AgentTask task = this.skill.in(5, procedure); - assertNotNull(task); - assertSame(procedure, task.getProcedure()); - ArgumentCaptor argument1 = ArgumentCaptor.forClass(Runnable.class); - ArgumentCaptor argument2 = ArgumentCaptor.forClass(Long.class); - ArgumentCaptor 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 atFixedDelay_zeroDelay() throws Exception { + runJanus(SchedulesRunTestAgent3.class, false); + assertEquals(2, getNumberOfResults()); + assertEquals(0, getResult(Integer.class, 0)); + assertEquals(1, getResult(Integer.class, 1)); + } - @Test - public void inAgentTaskLongProcedure1() { - 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.in(task, 5, procedure); - assertSame(task, t); - ArgumentCaptor argument0 = ArgumentCaptor.forClass(Procedure1.class); - Mockito.verify(task, new Times(1)).setProcedure(argument0.capture()); - assertSame(procedure, argument0.getValue()); - ArgumentCaptor argument1 = ArgumentCaptor.forClass(Runnable.class); - ArgumentCaptor argument2 = ArgumentCaptor.forClass(Long.class); - ArgumentCaptor 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()); - } + /** + * @author $Author: sgalland$ + * @version $FullVersion$ + * @mavengroupid $GroupId$ + * @mavenartifactid $ArtifactId$ + */ + @SarlSpecification(SARLVersion.SPECIFICATION_RELEASE_VERSION_STRING) + public static class SchedulesRunTestAgent3 extends TestingAgent { - @Test - public void everyLongProcedure1() { - Procedure1 procedure = Mockito.mock(Procedure1.class); - AgentTask task = this.skill.every(5, procedure); - assertNotNull(task); - assertSame(procedure, task.getProcedure()); - ArgumentCaptor argument1 = ArgumentCaptor.forClass(Runnable.class); - ArgumentCaptor argument2 = ArgumentCaptor.forClass(Long.class); - ArgumentCaptor argument3 = ArgumentCaptor.forClass(Long.class); - ArgumentCaptor argument4 = ArgumentCaptor.forClass(TimeUnit.class); - Mockito.verify(this.executorService, new Times(1)).scheduleAtFixedRate(argument1.capture(), argument2.capture(), - argument3.capture(), argument4.capture()); - assertNotNull(argument1.getValue()); - assertEquals(new Long(0), argument2.getValue()); - assertEquals(new Long(5), argument3.getValue()); - assertSame(TimeUnit.MILLISECONDS, argument4.getValue()); - } + private final AtomicInteger index = new AtomicInteger(); - @Test - public void everyAgentTaskLongProcedure1() { - 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.every(task, 5, procedure); - assertSame(task, t); - ArgumentCaptor argument0 = ArgumentCaptor.forClass(Procedure1.class); - Mockito.verify(task, new Times(1)).setProcedure(argument0.capture()); - assertSame(procedure, argument0.getValue()); - ArgumentCaptor argument1 = ArgumentCaptor.forClass(Runnable.class); - ArgumentCaptor argument2 = ArgumentCaptor.forClass(Long.class); - ArgumentCaptor argument3 = ArgumentCaptor.forClass(Long.class); - ArgumentCaptor argument4 = ArgumentCaptor.forClass(TimeUnit.class); - Mockito.verify(this.executorService, new Times(1)).scheduleAtFixedRate(argument1.capture(), argument2.capture(), - argument3.capture(), argument4.capture()); - assertNotNull(argument1.getValue()); - assertEquals(new Long(0), argument2.getValue()); - assertEquals(new Long(5), argument3.getValue()); - assertSame(TimeUnit.MILLISECONDS, argument4.getValue()); - } + public SchedulesRunTestAgent3(BuiltinCapacitiesProvider provider, UUID parentID, UUID agentID) { + super(provider, parentID, agentID); + } + + @Override + protected boolean runAgentTest() { + getSkill(Schedules.class).atFixedDelay(0, (it) -> { + addResult(this.index.getAndIncrement()); + if (this.index.get() >= 2) { + forceKillMe(); + } + }); + return false; + } - @Test - public void uninstall() throws Exception { - Procedure1 procedure1 = Mockito.mock(Procedure1.class); - this.skill.every(5, procedure1); - Procedure1 procedure2 = Mockito.mock(Procedure1.class); - this.skill.in(5, procedure2); - Collection> futures = (Collection>) this.reflect.invoke(this.skill, "getActiveFutures"); - assertEquals(2, futures.size()); - // - this.reflect.invoke(this.skill, "uninstall"); - // - Collection activeTasks = (Collection) this.reflect.invoke(this.skill, "getActiveTasks"); - assertTrue(activeTasks.isEmpty()); - for (ScheduledFuture f : futures) { - Mockito.verify(f, new Times(1)).cancel(ArgumentMatchers.anyBoolean()); } - } + } + + /** + * @author $Author: sgalland$ + * @version $FullVersion$ + * @mavengroupid $GroupId$ + * @mavenartifactid $ArtifactId$ + */ + @SarlSpecification(SARLVersion.SPECIFICATION_RELEASE_VERSION_STRING) + public static class SchedulesRunTestAgent4 extends TestingAgent { + + public SchedulesRunTestAgent4(BuiltinCapacitiesProvider provider, UUID parentID, UUID agentID) { + super(provider, parentID, agentID); + } + + @Override + protected boolean runAgentTest() { + getSkill(Schedules.class).execute((it) -> { + addResult(Boolean.TRUE); + forceKillMe(); + }); + return false; + } - @Test - public void cancelAgentTask() throws Exception { - Procedure1 procedure1 = Mockito.mock(Procedure1.class); - AgentTask t1 = this.skill.every(5, procedure1); - Procedure1 procedure2 = Mockito.mock(Procedure1.class); - AgentTask t2 = this.skill.in(5, procedure2); - Collection> futures = (Collection>) this.reflect.invoke(this.skill, "getActiveFutures"); - assertEquals(2, futures.size()); - // - this.skill.cancel(t2); - this.skill.cancel(t1); - // - Collection activeTasks = (Collection) this.reflect.invoke(this.skill, "getActiveTasks"); - assertTrue(activeTasks.isEmpty()); - for (ScheduledFuture f : futures) { - Mockito.verify(f, new Times(1)).cancel(ArgumentMatchers.anyBoolean()); } - } - @Test - public void cancelAgentTaskBoolean_true() throws Exception { - Procedure1 procedure1 = Mockito.mock(Procedure1.class); - AgentTask t1 = this.skill.every(5, procedure1); - Procedure1 procedure2 = Mockito.mock(Procedure1.class); - AgentTask t2 = this.skill.in(5, procedure2); - Collection> futures = (Collection>) this.reflect.invoke(this.skill, "getActiveFutures"); - assertEquals(2, futures.size()); - // - this.skill.cancel(t2, true); - this.skill.cancel(t1, true); - // - Collection activeTasks = (Collection) this.reflect.invoke(this.skill, "getActiveTasks"); - assertTrue(activeTasks.isEmpty()); - for (ScheduledFuture f : futures) { - Mockito.verify(f, new Times(1)).cancel(ArgumentMatchers.anyBoolean()); + @Test + public void cancel_infiniteLoop() throws Exception { + runJanus(SchedulesRunTestAgent5.class, false); + assertEquals(2, getNumberOfResults()); + assertEquals(0, getResult(Integer.class, 0)); + assertEquals(1, getResult(Integer.class, 1)); } - } - @Test - public void cancelAgentTaskBoolean_false() throws Exception { - Procedure1 procedure1 = Mockito.mock(Procedure1.class); - AgentTask t1 = this.skill.every(5, procedure1); - Procedure1 procedure2 = Mockito.mock(Procedure1.class); - AgentTask t2 = this.skill.in(5, procedure2); - Collection> futures = (Collection>) this.reflect.invoke(this.skill, "getActiveFutures"); - assertEquals(2, futures.size()); - // - this.skill.cancel(t2, false); - this.skill.cancel(t1, false); - // - Collection activeTasks = (Collection) this.reflect.invoke(this.skill, "getActiveTasks"); - assertTrue(activeTasks.isEmpty()); - for (ScheduledFuture f : futures) { - Mockito.verify(f, new Times(1)).cancel(ArgumentMatchers.anyBoolean()); + /** + * @author $Author: sgalland$ + * @version $FullVersion$ + * @mavengroupid $GroupId$ + * @mavenartifactid $ArtifactId$ + */ + @SarlSpecification(SARLVersion.SPECIFICATION_RELEASE_VERSION_STRING) + public static class SchedulesRunTestAgent5 extends TestingAgent { + + private final AtomicInteger index = new AtomicInteger(); + + public SchedulesRunTestAgent5(BuiltinCapacitiesProvider provider, UUID parentID, UUID agentID) { + super(provider, parentID, agentID); + } + + @Override + protected boolean runAgentTest() { + final AgentTask task = getSkill(Schedules.class).task(null); + getSkill(Schedules.class).atFixedDelay(task, 0, (it) -> { + if (this.index.get() >= 2) { + throw new IllegalStateException(); + } + addResult(this.index.getAndIncrement()); + if (this.index.get() >= 2) { + getSkill(Schedules.class).cancel(task); + } + SchedulesSkill skill = (SchedulesSkill) getSkill(Schedules.class); + if (skill.getActiveTasks().isEmpty()) { + forceKillMe(); + } + }); + return false; + } + } + + @Test + public void cancel_everyTask() throws Exception { + runJanus(SchedulesRunTestAgent6.class, false); + assertEquals(2, getNumberOfResults()); + assertEquals(0, getResult(Integer.class, 0)); + assertEquals(1, getResult(Integer.class, 1)); + } + + /** + * @author $Author: sgalland$ + * @version $FullVersion$ + * @mavengroupid $GroupId$ + * @mavenartifactid $ArtifactId$ + */ + @SarlSpecification(SARLVersion.SPECIFICATION_RELEASE_VERSION_STRING) + public static class SchedulesRunTestAgent6 extends TestingAgent { + + private final AtomicInteger index = new AtomicInteger(); + + public SchedulesRunTestAgent6(BuiltinCapacitiesProvider provider, UUID parentID, UUID agentID) { + super(provider, parentID, agentID); + } + + @Override + protected boolean runAgentTest() { + final AgentTask task = getSkill(Schedules.class).task(null); + getSkill(Schedules.class).every(task, 500, (it) -> { + if (this.index.get() >= 2) { + throw new IllegalStateException(); + } + addResult(this.index.getAndIncrement()); + if (this.index.get() >= 2) { + getSkill(Schedules.class).cancel(task); + } + SchedulesSkill skill = (SchedulesSkill) getSkill(Schedules.class); + if (skill.getActiveTasks().isEmpty()) { + forceKillMe(); + } + }); + return false; + } + + } + } } diff --git a/sre/io.janusproject/io.janusproject.tests/src/io/janusproject/tests/testutils/AbstractJanusRunTest.java b/sre/io.janusproject/io.janusproject.tests/src/io/janusproject/tests/testutils/AbstractJanusRunTest.java index 58fac1f51c..de91ee9452 100644 --- a/sre/io.janusproject/io.janusproject.tests/src/io/janusproject/tests/testutils/AbstractJanusRunTest.java +++ b/sre/io.janusproject/io.janusproject.tests/src/io/janusproject/tests/testutils/AbstractJanusRunTest.java @@ -310,6 +310,15 @@ protected void addResult(Object result) { this.results.add(result); } + /** + * Replies the number of results provided by the ran platform. + * + * @return the number of results. + */ + protected int getNumberOfResults() { + return this.results.size(); + } + @PerceptGuardEvaluator private void $guardEvaluator$Initialize(final Initialize occurrence, final Collection ___SARLlocal_runnableCollection) { assert occurrence != null; @@ -326,8 +335,7 @@ protected void addResult(Object result) { this.results = (List) occurrence.parameters[0]; try { if (runAgentTest()) { - getSkill(Schedules.class).in(1000, (it) -> - getSkill(Lifecycle.class).killMe()); + getSkill(Schedules.class).in(1000, (it) -> forceKillMe()); } } catch (Throwable exception) { if (!(exception instanceof ChuckNorrisException)) { @@ -337,6 +345,10 @@ protected void addResult(Object result) { } } + protected void forceKillMe() { + getSkill(Lifecycle.class).killMe(); + } + /** * Invoked to run the unit test. *