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) ]
+ *
+ *
+ *
+ *
+ *
+ * t= 0 500 1000 1500 2000 2500 3000 3500 4000 4500 50005500 6000 6500
+ *
+ *
+ * A X X X X
+ * B X X X X
+ * C X X X X
+ *
+ *
+ *
+ * @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 super Agent> procedure) {
@Override
public synchronized AgentTask in(AgentTask task, long delay, Procedure1 super Agent> 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 super
@Override
public synchronized AgentTask task(String name) {
- if (this.tasks.containsKey(name)) {
- return this.tasks.get(name);
+ final String realName = Strings.isNullOrEmpty(name) ? "task-" + UUID.randomUUID() : name; //$NON-NLS-1$
+ if (this.tasks.containsKey(realName)) {
+ return this.tasks.get(realName);
}
final AgentTask t = new AgentTask();
- t.setName(name);
- t.setGuard(new Function1() {
-
- @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 super Agent> procedure) {
@Override
public synchronized AgentTask every(AgentTask task, long period, Procedure1 super Agent> 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 su
return rtask;
}
+ @Override
+ public AgentTask atFixedDelay(long delay, Procedure1 super Agent> procedure) {
+ return atFixedDelay(Schedules.$DEFAULT_VALUE$ATFIXEDDELAY_0, delay, procedure);
+ }
+
+ @Override
+ public synchronized AgentTask atFixedDelay(AgentTask task, long delay, Procedure1 super Agent> 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 super Agent> 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 super Agent> 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 super Agent> 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 super Agent> 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.
*