/* * $Id$ * * Janus platform is an open-source multiagent platform. * More details on http://www.janusproject.io * * Copyright (C) 2014-2015 Sebastian RODRIGUEZ, Nicolas GAUD, Stéphane GALLAND. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.janusproject.tests.bugs; import static org.junit.Assert.*; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Random; import java.util.Set; import java.util.TreeSet; import java.util.UUID; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; import io.janusproject.kernel.Kernel; import io.janusproject.tests.testutils.AbstractJanusRunTest; import io.sarl.core.AgentKilled; import io.sarl.core.AgentTask; import io.sarl.core.DefaultContextInteractions; import io.sarl.core.Initialize; import io.sarl.core.Lifecycle; import io.sarl.core.Schedules; import io.sarl.lang.SARLVersion; import io.sarl.lang.annotation.PerceptGuardEvaluator; import io.sarl.lang.annotation.SarlSpecification; import io.sarl.lang.core.Agent; import io.sarl.lang.core.BuiltinCapacitiesProvider; import io.sarl.lang.core.Event; import io.sarl.util.Scopes; /** * Unit test for the issue #546: Not enough AgentKilled occurrences after killMe() calls. * * @author $Author: sgalland$ * @version $FullVersion$ * @mavengroupid $GroupId$ * @mavenartifactid $ArtifactId$ * @see https://github.com/sarl/sarl/issues/546 */ @RunWith(Suite.class) @SuiteClasses({ Bug546.NoRandomWaiting.class, Bug546.RandomWaiting.class, Bug546.HugeEventSetTest.class, }) @SuppressWarnings("all") public class Bug546 { private static final boolean LOG = false; private static final int NB_AGENTS = 300; private static final int NB_EVENTS = 500; private static final int BASE_DELAY = 500; private static final int MAX_EXTRA_DELAY = 2000; private static final int PRESENTATION_DELAY = 1000; public static abstract class AbstractBugS546Test extends AbstractJanusRunTest { @Test public void waitAgentKilled() throws Exception { Kernel kernel = setupTheJanusKernel(KillWaiterAgent.class, false, true); List<UUID> ids = new ArrayList<>(NB_AGENTS); for (int i = 0; i < NB_AGENTS; ++i) { UUID id = spawn(kernel); ids.add(id); } try { waitForTheKernel(EXTRA_TIMEOUT); } catch (TimeoutException e) { if (LOG) { System.err.println(getResults()); } throw e; } assertEquals(NB_AGENTS, getNumberOfResults()); assertContains(getResults(), ids.toArray()); } protected abstract UUID spawn(Kernel kernel); @SarlSpecification(SARLVersion.SPECIFICATION_RELEASE_VERSION_STRING) public static abstract class AbstractKillableAgent extends TestingAgent { private AgentTask task; public AbstractKillableAgent(BuiltinCapacitiesProvider provider, UUID parentID, UUID agentID) { super(provider, parentID, agentID); } @Override protected boolean runAgentTest() { if (LOG) { System.out.println("K-" + getID() + ": starting"); } final Schedules s = getSkill(Schedules.class); this.task = s.task(null); s.every(this.task, PRESENTATION_DELAY, (it) -> { if (LOG) { System.out.println("K-" + getID() + ": send presentation"); } getSkill(DefaultContextInteractions.class).emit(new PresentationEvent()); }); return false; } @PerceptGuardEvaluator private void shootGuardEvaluator(ShootEvent occurrence, Collection<Runnable> ___SARLlocal_runnableCollection) { assert occurrence != null; assert ___SARLlocal_runnableCollection != null; ___SARLlocal_runnableCollection.add(() -> shootBehaviorUnitPrivate(occurrence)); } private void shootBehaviorUnitPrivate(ShootEvent occurrence) { Schedules s = getSkill(Schedules.class); s.cancel(this.task); if (LOG) { System.out.println("K-" + getID() + ": cancel presentation task"); System.out.println("K-" + getID() + ": run shoot behavior"); } shootBehaviorUnit(occurrence); } protected abstract void shootBehaviorUnit(ShootEvent occurrence); } @SarlSpecification(SARLVersion.SPECIFICATION_RELEASE_VERSION_STRING) public static class KillWaiterAgent extends TestingAgent { private final Set<UUID> presentedAgents = new TreeSet<>(); private final Set<UUID> shootedAgents = new TreeSet<>(); private final AtomicInteger feedbacks = new AtomicInteger(); private final AtomicInteger guards = new AtomicInteger(); public KillWaiterAgent(BuiltinCapacitiesProvider provider, UUID parentID, UUID agentID) { super(provider, parentID, agentID); } @Override protected boolean runAgentTest() { final Schedules s = getSkill(Schedules.class); final AgentTask task = s.task(null); s.every(task, 500, (it) -> { final int nb; synchronized (this.presentedAgents) { nb = this.presentedAgents.size(); } if (LOG) { System.out.println("W: receiving " + nb + " agent presentation(s)"); } if (nb >= NB_AGENTS && !s.isCanceled(task)) { s.cancel(task); if (LOG) { System.out.println("W: waiting task canceled"); System.out.println("W: shoot the guys"); } getSkill(DefaultContextInteractions.class).emit(new ShootEvent()); } }); if (LOG) { s.every(1000, (it) -> { final int nb1; synchronized (this.presentedAgents) { nb1 = this.presentedAgents.size(); } final int nb2; synchronized (this.shootedAgents) { nb2 = this.shootedAgents.size(); } final int nb3 = getSkill(DefaultContextInteractions.class).getDefaultSpace().getParticipants().size(); System.out.println("INFO: present=" + nb1 + "; killed=" + nb2 + "; inSpace=" + nb3); System.out.flush(); }); } return false; } @PerceptGuardEvaluator private void initializeGuardEvaluator(PresentationEvent occurrence, Collection<Runnable> ___SARLlocal_runnableCollection) { assert occurrence != null; assert ___SARLlocal_runnableCollection != null; ___SARLlocal_runnableCollection.add(() -> initializeBehaviorUnit(occurrence)); } private void initializeBehaviorUnit(PresentationEvent occurrence) { final boolean b; synchronized (this.presentedAgents) { b = this.presentedAgents.add(occurrence.getSource().getUUID()); } if (!b) { if (LOG) { System.out.println("W: again K-" + occurrence.getSource().getUUID()); } } else if (LOG) { System.out.println("W: hello K-" + occurrence.getSource().getUUID()); } } @PerceptGuardEvaluator private void agentKilledGuardEvaluator(AgentKilled occurrence, Collection<Runnable> ___SARLlocal_runnableCollection) { assert occurrence != null; assert ___SARLlocal_runnableCollection != null; if (LOG) { System.out.println("W: guard evaluation #" + guards.incrementAndGet()) ; } if (!isFromMe(occurrence)) { ___SARLlocal_runnableCollection.add(() -> agentKilledBehaviorUnit(occurrence)); } } private void agentKilledBehaviorUnit(AgentKilled occurrence) { if (LOG) { System.out.println("W: feedback #" + feedbacks.incrementAndGet()) ; } final boolean b; final int size1; synchronized (this.presentedAgents) { b = this.presentedAgents.remove(occurrence.getSource().getUUID()); size1 = this.presentedAgents.size(); } if (b) { if (LOG) { System.out.println("W: agent K-" + occurrence.getSource().getUUID() + " killed") ; System.out.println("W: remaining " + size1 + " agent(s)") ; } final int size2; synchronized (this.shootedAgents) { this.shootedAgents.add(occurrence.getSource().getUUID()); size2 = this.shootedAgents.size(); } if (LOG) { System.out.println("W: living agents = " + size1) ; System.out.println("W: killed agents = " + size2) ; } if (size2 >= NB_AGENTS) { if (LOG) { System.out.println("W: Stop unit test"); } synchronized (this.shootedAgents) { addResults(this.shootedAgents); } getSkill(Lifecycle.class).killMe(); } } else if (LOG) { System.out.println("W: IGNORE AGENT KILLED FOR " + occurrence.getSource().getUUID()); } } } } public static class PresentationEvent extends Event { } public static class ShootEvent extends Event { } public static class NoRandomWaiting extends AbstractBugS546Test { @SarlSpecification(SARLVersion.SPECIFICATION_RELEASE_VERSION_STRING) public static class NotRandomKillableAgent extends AbstractKillableAgent { public NotRandomKillableAgent(BuiltinCapacitiesProvider provider, UUID parentID, UUID agentID) { super(provider, parentID, agentID); } protected void shootBehaviorUnit(ShootEvent occurrence) { if (LOG) { System.out.println("K-" + getID() + ": bye bye"); } getSkill(Lifecycle.class).killMe(); } } @Override protected UUID spawn(Kernel kernel) { return kernel.spawn(NotRandomKillableAgent.class, getAgentInitializationParameters()); } } public static class RandomWaiting extends AbstractBugS546Test { private static final Random RANDOM = new Random(); @SarlSpecification(SARLVersion.SPECIFICATION_RELEASE_VERSION_STRING) public static class RandomKillableAgent extends AbstractKillableAgent { public RandomKillableAgent(BuiltinCapacitiesProvider provider, UUID parentID, UUID agentID) { super(provider, parentID, agentID); } protected void shootBehaviorUnit(ShootEvent occurrence) { long delay = RANDOM.nextInt(MAX_EXTRA_DELAY) + BASE_DELAY; if (LOG) { System.out.println("I'M SHOOT -> commit suicide in " + delay + " ms: " + getID()); } getSkill(Schedules.class).in(delay, (it) -> { if (LOG) { System.out.println("Commit suicide now: " + getID()); } getSkill(Lifecycle.class).killMe(); }); } } @Override protected UUID spawn(Kernel kernel) { return kernel.spawn(RandomKillableAgent.class, getAgentInitializationParameters()); } } public static class HugeEventSetTest extends AbstractJanusRunTest { @Test public void sendEvents() throws Exception { Kernel kernel = setupTheJanusKernel(ReceivingAgent.class, false, true); kernel.spawn(SendingAgent.class); try { waitForTheKernel(EXTRA_TIMEOUT); } catch (TimeoutException e) { if (LOG) { System.err.println(getResults()); } throw e; } assertEquals(NB_EVENTS, getNumberOfResults()); for (Object result : getResults()) { assertTrue(result instanceof HugeEventSetEvent); } } @SarlSpecification(SARLVersion.SPECIFICATION_RELEASE_VERSION_STRING) public static class SendingAgent extends TestingAgent { private final AtomicBoolean treated = new AtomicBoolean(false); public SendingAgent(BuiltinCapacitiesProvider provider, UUID parentID, UUID agentID) { super(provider, parentID, agentID); } @Override protected boolean runAgentTest() { return false; } @PerceptGuardEvaluator private void guardEvaluator1(PresentationEvent occurrence, Collection<Runnable> ___SARLlocal_runnableCollection) { assert occurrence != null; assert ___SARLlocal_runnableCollection != null; if (treated.getAndSet(true)) { ___SARLlocal_runnableCollection.add(() -> eventHandler1(occurrence)); } } private void eventHandler1(PresentationEvent occurrence) { assert occurrence != null; getSkill(Schedules.class).in(1000, (agent) -> { DefaultContextInteractions skill = getSkill(DefaultContextInteractions.class); for (int i = 0; i < NB_EVENTS; ++i) { skill.emit(new HugeEventSetEvent(), Scopes.notAddresses(skill.getDefaultAddress())); } }); } } @SarlSpecification(SARLVersion.SPECIFICATION_RELEASE_VERSION_STRING) public static class ReceivingAgent extends TestingAgent { private AgentTask task; public ReceivingAgent(BuiltinCapacitiesProvider provider, UUID parentID, UUID agentID) { super(provider, parentID, agentID); } @Override protected boolean runAgentTest() { final Schedules schedules = getSkill(Schedules.class); this.task = schedules.task(null); schedules.every(this.task, PRESENTATION_DELAY, (agent) -> { DefaultContextInteractions ctx = getSkill(DefaultContextInteractions.class); ctx.emit(new PresentationEvent(), Scopes.notAddresses(ctx.getDefaultAddress())); }); return false; } @PerceptGuardEvaluator private void guardEvaluator(HugeEventSetEvent occurrence, Collection<Runnable> ___SARLlocal_runnableCollection) { assert occurrence != null; assert ___SARLlocal_runnableCollection != null; AgentTask tsk = this.task; if (tsk != null) { this.task = null; getSkill(Schedules.class).cancel(tsk); } ___SARLlocal_runnableCollection.add(() -> eventHandler(occurrence)); } private void eventHandler(HugeEventSetEvent occurrence) { assert occurrence != null; addResult(occurrence); } } @SarlSpecification(SARLVersion.SPECIFICATION_RELEASE_VERSION_STRING) public static final class HugeEventSetEvent extends Event { } } }