Skip to content
This repository has been archived by the owner on Aug 23, 2023. It is now read-only.

Commit

Permalink
[kernel] Stop the agent when an exception occured in the Initialize h…
Browse files Browse the repository at this point in the history
…andler.

see #91

Signed-off-by: Stéphane Galland <galland@arakhne.org>
  • Loading branch information
gallandarakhneorg committed Feb 23, 2015
1 parent a864941 commit fc6cc5c
Show file tree
Hide file tree
Showing 4 changed files with 177 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@

import io.janusproject.services.executor.ChuckNorrisException;
import io.janusproject.services.logging.LogService;
import io.janusproject.services.spawn.SpawnService;
import io.sarl.core.Initialize;
import io.sarl.lang.core.Agent;

import java.lang.Thread.UncaughtExceptionHandler;
import java.util.concurrent.CancellationException;
Expand All @@ -47,6 +50,9 @@ public class JdkUncaughtExceptionHandler implements UncaughtExceptionHandler, Su

private final LogService logger;

@Inject
private SpawnService spawnService;

/**
* @param logger - the logging service that must be used for output the errors.
*/
Expand Down Expand Up @@ -112,12 +118,33 @@ public void uncaughtException(Thread t, Throwable e) {
log(e, Long.toString(t.getId()), t.getName());
}

/** Replies if the given object is an event that may cause agent stop when an error occured in the event's handler.
*
* @param o - the event to test.
* @return <code>true</code> if the agent must stop if an error occured in the handler for the given event.
*/
@SuppressWarnings("static-method")
public boolean isAutoKillEvent(Object o) {
return o instanceof Initialize;
}

/** {@inheritDoc}
*/
@Override
public void handleException(Throwable exception,
SubscriberExceptionContext context) {
log(exception, context.getEventBus().toString(), context.getEvent().toString());

// #91: Special case: when the agent cannot be initialized, it must be destroyed
if (isAutoKillEvent(context.getEvent())) {
Agent caller = (Agent) context.getSubscriber();
try {
// Do not call the equivalent of the agent's killMe since the agent was never initialized.
this.spawnService.killAgent(caller.getID());
} catch (Exception e) {
log(e, context.getEventBus().toString(), context.getEvent().toString());
}
}
}

}
Expand Down
101 changes: 101 additions & 0 deletions io.janusproject.kernel/src/test/java/io/janusproject/bugs/Bug91.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* $Id$
*
* Janus platform is an open-source multiagent platform.
* More details on http://www.janusproject.io
*
* Copyright (C) 2014 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.bugs;

import io.janusproject.Boot;
import io.janusproject.testutils.AbstractJanusRunTest;

import java.util.UUID;

import org.junit.Before;
import org.junit.Test;

import com.google.common.eventbus.SubscriberExceptionHandler;
import com.google.inject.Inject;

import static org.junit.Assert.*;

/** Unit test for the issue #91: Stop agent on initialization failure?
*
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
* @see https://github.com/janus-project/janusproject/issues/91
*/
@SuppressWarnings("all")
public class Bug91 extends AbstractJanusRunTest {

@Inject
private SubscriberExceptionHandler uncaughtEventBusExceptionHandler;

@Before
public void setUp() {
Boot.setOffline(true);
}

@Test
public void ExceptionInInit() throws Exception {
runJanus(ExceptionInInitAgent.class);
assertNumberOfResults(1);
Exception ex = getResult(Exception.class, 0);
assertNotNull(ex);
assertCause(TestException.class, ex);
}

/**
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
*/
public static class ExceptionInInitAgent extends TestingAgent {

public ExceptionInInitAgent(UUID parentID) {
super(parentID);
}

public ExceptionInInitAgent(UUID parentID, UUID agentID) {
super(parentID, agentID);
}

@Override
protected boolean runAgentTest() {
throw new TestException();
}

}

/**
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
*/
private static class TestException extends RuntimeException {

public TestException() {
super("Error in the agent");
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
*/
package io.janusproject.testutils;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import io.janusproject.Boot;
import io.janusproject.kernel.Kernel;
Expand Down Expand Up @@ -92,6 +93,22 @@ protected void finished(Description description) {
}
}
};

/** Replies the number of results provided by the ran platform.
*
* @return the number of results.
*/
protected int getNumberOfResults() {
return this.results.size();
}

/** Test if the number of results provided by the Janus platform is equal to the given number.
*
* @param expected - the expected number of results.
*/
protected void assertNumberOfResults(int expected) {
assertEquals("Invalid number of results provided by the platform.", expected, this.results.size());
}

/** Replies result at the given index of the run of the agent.
*
Expand Down Expand Up @@ -142,7 +159,7 @@ protected int indexOfResult(Class<?> type, int fromIndex) {
return -1;
}

/** Start the Janus platform.
/** Start the Janus platform offline.
*
* This function has no timeout for the end of the run.
*
Expand All @@ -151,10 +168,10 @@ protected int indexOfResult(Class<?> type, int fromIndex) {
* @throws Exception - if the kernel cannot be launched.
*/
protected void runJanus(Class<? extends TestingAgent> type, boolean enableLogging) throws Exception {
runJanus(type, enableLogging, -1);
runJanus(type, enableLogging, true, -1);
}

/** Start the Janus platform.
/** Start the Janus platform offline with logging enabled.
*
* This function enables logging and has no timeout for the end of the run.
*
Expand All @@ -163,17 +180,18 @@ protected void runJanus(Class<? extends TestingAgent> type, boolean enableLoggin
* @throws Exception - if the kernel cannot be launched.
*/
protected void runJanus(Class<? extends TestingAgent> type) throws Exception {
runJanus(type, true, -1);
runJanus(type, true, true, -1);
}

/** Start the Janus platform.
*
* @param type - the type of the agent to launch at start-up.
* @param enableLogging - indicates if the logging is enable or not.
* @param offline - indicates if the Janus platform is offline
* @param timeout - the maximum waiting time in seconds, or <code>-1</code> to ignore the timeout.
* @throws Exception - if the kernel cannot be launched.
*/
protected void runJanus(Class<? extends TestingAgent> type, boolean enableLogging, int timeout) throws Exception {
protected void runJanus(Class<? extends TestingAgent> type, boolean enableLogging, boolean offline, int timeout) throws Exception {
assertNull("Janus already launched.", this.janusKernel);
Module module = new StandardJanusPlatformModule();
Boot.setConsoleLogger(new PrintStream(new OutputStream() {
Expand All @@ -188,6 +206,7 @@ public void write(int b) throws IOException {
} else {
module = Modules.override(new StandardJanusPlatformModule()).with(new ErrorLogTestingModule(this.results));
}
Boot.setOffline(offline);
this.janusKernel = Boot.startJanus(
module,
type,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
*/
package io.janusproject.testutils;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.*;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
Expand Down Expand Up @@ -117,6 +117,30 @@ protected void finished(Description description) {
resetProperties();
}
};

/** Test if the given exception has a cause of the given type.
*
* If the given exception has no cause, it is the cause.
*
* @param <T> - the type of the expected cause.
* @param expected - the type of the expected cause.
* @param actual - the exception to test.
* @return the cause.
*/
public static <T extends Throwable> T assertCause(Class<T> expected, Throwable actual) {
Throwable cause = actual;
while (cause != null && cause.getCause() != null && cause.getCause() != cause) {
cause = cause.getCause();
}
if (cause == null) {
cause = actual;
}
assertTrue("Unexpected type of exception's cause. Expected: "
+ expected.getName() + ". Actual: "
+ cause.getClass().getName(),
expected.isInstance(cause));
return expected.cast(cause);
}

/** Test if the actual collection/iterable contains all the expected objects.
*
Expand Down

0 comments on commit fc6cc5c

Please sign in to comment.