/*
* Copyright (C) 2011 Red Hat, Inc. and/or its affiliates.
*
* 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 org.jboss.errai.bus.client.tests;
import java.util.ArrayList;
import java.util.Collection;
import org.jboss.errai.bus.client.api.Subscription;
import org.jboss.errai.bus.client.api.base.DefaultErrorCallback;
import org.jboss.errai.bus.client.api.base.MessageBuilder;
import org.jboss.errai.bus.client.api.base.NoSubscribersToDeliverTo;
import org.jboss.errai.bus.client.api.messaging.Message;
import org.jboss.errai.bus.client.tests.support.ErrorThrowingRPCService;
import org.jboss.errai.bus.client.tests.support.SimpleRPCService;
import org.jboss.errai.bus.common.AbstractErraiTest;
import org.jboss.errai.common.client.api.ErrorCallback;
import org.jboss.errai.common.client.protocols.MessageParts;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.GWT.UncaughtExceptionHandler;
import com.google.gwt.user.client.Timer;
/**
* Error handling tests
*
* @author Christian Sadilek <csadilek@redhat.com>
*/
public class ErrorHandlingTest extends AbstractErraiTest {
private static final String LOCAL_ERROR_THROWING_SERVICE = "LocalErrorThrowingService";
private static class Ref<T> {
T value;
public Ref(final T initial) {
this.value = initial;
}
}
private final Collection<Subscription> subscriptions = new ArrayList<>();
@Override
public String getModuleName() {
return "org.jboss.errai.bus.ErraiBusTests";
}
@Override
protected void gwtSetUp() throws Exception {
GWT.setUncaughtExceptionHandler(e -> {
if (e instanceof AssertionError) {
throw (AssertionError) e;
}
});
super.gwtSetUp();
subscriptions.add(bus.subscribe(LOCAL_ERROR_THROWING_SERVICE, m -> {
throw new RuntimeException("Thrown by " + LOCAL_ERROR_THROWING_SERVICE);
}));
}
@Override
protected void gwtTearDown() throws Exception {
for (final Subscription sub : subscriptions) {
sub.remove();
}
subscriptions.clear();
super.gwtTearDown();
}
public void testDefaultErrorHandlerCallsGwtUncaughtExceptionHandler() throws Exception {
runAfterInit(() -> {
final Throwable t = new Throwable();
final Ref<Throwable> caughtRef = new Ref<>(null);
GWT.setUncaughtExceptionHandler(caught -> {
caughtRef.value = caught;
});
MessageBuilder
.createMessage(DefaultErrorCallback.CLIENT_ERROR_SUBJECT)
.with(MessageParts.Throwable, t)
.noErrorHandling()
.sendNowWith(bus);
assertSame(t, caughtRef.value);
finishTest();
});
}
public void testRemoteDefaultErrorHandling() {
final String subject = "ErrorThrowingService";
runAfterInit(() -> {
subscriptions.add(bus.subscribe(DefaultErrorCallback.CLIENT_ERROR_SUBJECT, message -> {
final Throwable thrown = message.get(Throwable.class, MessageParts.Throwable);
assertTrue(thrown instanceof RuntimeException);
assertTrue(thrown.getMessage().contains(subject));
finishTest();
}));
MessageBuilder
.createMessage(subject)
.signalling()
.defaultErrorHandling()
.sendNowWith(bus);
});
}
public void testRemoteNoErrorHandling() {
final String subject = "ErrorThrowingService";
runAfterInit(() -> {
subscriptions.add(bus.subscribe(DefaultErrorCallback.CLIENT_ERROR_SUBJECT, message -> {
fail("Should not have received message on " + DefaultErrorCallback.CLIENT_ERROR_SUBJECT);
}));
final Timer finishTimer = new Timer() {
@Override
public void run() {
finishTest();
}
};
subscriptions.add(() -> finishTimer.cancel());
finishTimer.schedule(5000);
MessageBuilder
.createMessage(subject)
.signalling()
.noErrorHandling()
.sendNowWith(bus);
});
}
public void testLocalDefaultErrorHandling() {
final String subject = LOCAL_ERROR_THROWING_SERVICE;
runAfterInit(() -> {
subscriptions.add(bus.subscribe(DefaultErrorCallback.CLIENT_ERROR_SUBJECT, message -> {
final Throwable thrown = message.get(Throwable.class, MessageParts.Throwable);
assertTrue(thrown instanceof RuntimeException);
assertTrue(thrown.getMessage().contains(subject));
finishTest();
}));
MessageBuilder
.createMessage(subject)
.signalling()
.defaultErrorHandling()
.sendNowWith(bus);
});
}
public void testLocalNoErrorHandling() {
final String subject = LOCAL_ERROR_THROWING_SERVICE;
runAfterInit(() -> {
subscriptions.add(bus.subscribe(DefaultErrorCallback.CLIENT_ERROR_SUBJECT, message -> {
fail("Should not have received message on " + DefaultErrorCallback.CLIENT_ERROR_SUBJECT);
}));
final Timer finishTimer = new Timer() {
@Override
public void run() {
finishTest();
}
};
subscriptions.add(() -> finishTimer.cancel());
finishTimer.schedule(5000);
MessageBuilder
.createMessage(subject)
.signalling()
.noErrorHandling()
.sendNowWith(bus);
});
}
public void testLocalCustomAndDefaultErrorHandling() {
final String subject = "NonExistentService";
runAfterInit(() -> {
final Ref<Boolean> ref = new Ref<>(false);
subscriptions.add(bus.subscribe(DefaultErrorCallback.CLIENT_ERROR_SUBJECT, message -> {
final Throwable thrown = message.get(Throwable.class, MessageParts.Throwable);
assertTrue(thrown instanceof NoSubscribersToDeliverTo);
assertTrue(ref.value);
finishTest();
}));
MessageBuilder
.createMessage(subject)
.signalling()
.errorsHandledBy((ErrorCallback<Message>) (m, t) -> {
ref.value = true;
return true;
})
.sendNowWith(bus);
});
}
public void testLocalCustomOnlyErrorHandling() {
final String subject = "NonExistentService";
runAfterInit(() -> {
subscriptions.add(bus.subscribe(DefaultErrorCallback.CLIENT_ERROR_SUBJECT, message -> {
fail("Should not have received error on subject " + DefaultErrorCallback.CLIENT_ERROR_SUBJECT);
}));
MessageBuilder
.createMessage(subject)
.signalling()
.errorsHandledBy((ErrorCallback<Message>) (m, t) -> {
final Timer finishTimer = new Timer() {
@Override
public void run() {
finishTest();
}
};
subscriptions.add(() -> {
finishTimer.cancel();
});
finishTimer.schedule(5000);
return false;
})
.sendNowWith(bus);
});
}
public void testRemoteRPCDefaultErrorHandling() {
runAfterInit(() -> {
subscriptions.add(bus.subscribe(DefaultErrorCallback.CLIENT_ERROR_SUBJECT, message -> {
final Throwable thrown = message.get(Throwable.class, MessageParts.Throwable);
assertNotNull(thrown);
assertNotNull(thrown.getMessage());
assertTrue(thrown.getMessage().contains(ErrorThrowingRPCService.class.getSimpleName()));
finishTest();
}));
MessageBuilder
.createCall((final Long time) -> fail("Should not receive response."), ErrorThrowingRPCService.class)
.currentTime();
});
}
public void testRemoteRPCCustomOnlyErrorHandling() {
runAfterInit(() -> {
subscriptions.add(bus.subscribe(DefaultErrorCallback.CLIENT_ERROR_SUBJECT, message -> {
fail("Should not have received error on subject " + DefaultErrorCallback.CLIENT_ERROR_SUBJECT);
}));
MessageBuilder
.createCall((final Long time) -> fail("Should not receive response."),
(m, t) -> {
final Timer finishTimer = new Timer() {
@Override
public void run() {
finishTest();
}
};
subscriptions.add(() -> {
finishTimer.cancel();
});
finishTimer.schedule(5000);
return false;
},
ErrorThrowingRPCService.class)
.currentTime();
});
}
public void testRemoteRPCCustomAndDefaultErrorHandling() {
runAfterInit(() -> {
subscriptions.add(bus.subscribe(DefaultErrorCallback.CLIENT_ERROR_SUBJECT, message -> {
final Throwable thrown = message.get(Throwable.class, MessageParts.Throwable);
assertNotNull(thrown);
assertNotNull(thrown.getMessage());
assertTrue(thrown.getMessage().contains(ErrorThrowingRPCService.class.getSimpleName()));
finishTest();
}));
MessageBuilder
.createCall((final Long time) -> fail("Should not receive response."),
(m, t) -> {
assertNotNull(t);
assertNotNull(t.getMessage());
assertTrue(t.getMessage().contains(ErrorThrowingRPCService.class.getSimpleName()));
return true;
},
ErrorThrowingRPCService.class)
.currentTime();
});
}
public void testRemoteRPCUncaughtExceptionHandlerInvokedForErrorInClientCallback() {
runAfterInit(() -> {
final Timer failTimer = new Timer() {
@Override
public void run() {
fail("Timed-out without UncaughtExceptionHandler being invoked.");
}
};
final UncaughtExceptionHandler handler = t -> {
if (t instanceof AssertionError) {
throw (AssertionError) t;
}
else {
finishTest();
}
};
GWT.setUncaughtExceptionHandler(handler);
subscriptions.add(() -> failTimer.cancel());
MessageBuilder
.createCall((final Long time) -> {
throw new RuntimeException("Client callback exception.");
}, ErrorThrowingRPCService.class)
.currentTime();
failTimer.schedule(5000);
});
}
public void testRemoteRPCUncaughtExceptionHandlerInvokedWhenErrorHandlerSetForErrorInClientCallback() {
runAfterInit(() -> {
final Timer failTimer = new Timer() {
@Override
public void run() {
fail("Timed-out without UncaughtExceptionHandler being invoked.");
}
};
final UncaughtExceptionHandler handler = t -> {
if (t instanceof AssertionError) {
throw (AssertionError) t;
}
else {
finishTest();
}
};
GWT.setUncaughtExceptionHandler(handler);
subscriptions.add(() -> failTimer.cancel());
MessageBuilder
.createCall((final Long time) -> {
throw new RuntimeException("Client callback exception.");
},
(m, t) -> {
fail("Should not invoke error handler for error in client callback.");
return false;
},
SimpleRPCService.class)
.currentTime();
failTimer.schedule(5000);
});
}
}