From 5b2ddc15bd2c30d9f9033a0c4cf50e32827ef0c6 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Wed, 13 Nov 2013 14:56:06 +0200 Subject: Make test work reliably by activating @Push Additional test now ensures that access() works both when called before init() is done and after init() is done Change-Id: Id56bd09f1aaa7a6a99eed8d097f12910cdc11596 --- uitest/src/com/vaadin/tests/push/PushFromInit.java | 53 +++++++++++++++++----- .../com/vaadin/tests/push/PushFromInitTest.java | 28 ++++-------- 2 files changed, 50 insertions(+), 31 deletions(-) diff --git a/uitest/src/com/vaadin/tests/push/PushFromInit.java b/uitest/src/com/vaadin/tests/push/PushFromInit.java index cb084f1232..0afaa866f7 100644 --- a/uitest/src/com/vaadin/tests/push/PushFromInit.java +++ b/uitest/src/com/vaadin/tests/push/PushFromInit.java @@ -15,29 +15,60 @@ */ package com.vaadin.tests.push; +import com.vaadin.annotations.Push; import com.vaadin.server.VaadinRequest; import com.vaadin.tests.components.AbstractTestUIWithLog; import com.vaadin.ui.Button; +@Push public class PushFromInit extends AbstractTestUIWithLog { + public static final String LOG_DURING_INIT = "Logged from access run before init ends"; + public static final String LOG_AFTER_INIT = "Logged from background thread run after init has finished"; + @Override protected void setup(VaadinRequest request) { - new Thread() { - @Override - public void run() { - access(new Runnable() { - @Override - public void run() { - log("Logged from background thread started in init"); - } - }); - } - }.start(); log("Logged in init"); + Thread t = new Thread(new RunBeforeInitEnds()); + t.start(); + try { + t.join(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + new Thread(new RunAfterInit()).start(); addComponent(new Button("Sync")); } + class RunBeforeInitEnds implements Runnable { + @Override + public void run() { + access(new Runnable() { + @Override + public void run() { + log(LOG_DURING_INIT); + } + }); + } + } + + class RunAfterInit implements Runnable { + @Override + public void run() { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + access(new Runnable() { + @Override + public void run() { + log(LOG_AFTER_INIT); + } + }); + } + } + @Override protected String getTestDescription() { return "Pusing something to a newly created UI should not cause race conditions"; diff --git a/uitest/src/com/vaadin/tests/push/PushFromInitTest.java b/uitest/src/com/vaadin/tests/push/PushFromInitTest.java index 3c1bc1b610..4101de29cf 100644 --- a/uitest/src/com/vaadin/tests/push/PushFromInitTest.java +++ b/uitest/src/com/vaadin/tests/push/PushFromInitTest.java @@ -15,8 +15,9 @@ */ package com.vaadin.tests.push; -import org.junit.Assert; import org.junit.Test; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.support.ui.ExpectedCondition; import com.vaadin.tests.tb3.MultiBrowserTest; @@ -25,26 +26,13 @@ public class PushFromInitTest extends MultiBrowserTest { public void testPushFromInit() { openTestURL(); - for (int second = 0;; second++) { - if (second >= 30) { - Assert.fail("timeout"); + waitUntil(new ExpectedCondition() { + @Override + public Boolean apply(WebDriver input) { + return ("3. " + PushFromInit.LOG_AFTER_INIT) + .equals(getLogRow(0)); } - try { - if ("1. Logged in init".equals(vaadinElementById( - "Log_row_1").getText())) { - break; - } - } catch (Exception e) { - } - try { - Thread.sleep(200); - } catch (InterruptedException e) { - } - } - - Assert.assertEquals( - "2. Logged from background thread started in init", - vaadinElementById("Log_row_0").getText()); + }); } } \ No newline at end of file -- cgit v1.2.3 From 10ca7ed57149eb20d8be936e9e060311b72298bb Mon Sep 17 00:00:00 2001 From: Henri Sara Date: Wed, 27 Nov 2013 15:30:36 +0200 Subject: Catch and log exceptions in session lifecycle listeners (#12915) Change-Id: Ie8638f010d74c569c5ff56e91c95e23a5cb92c9b --- server/src/com/vaadin/event/EventRouter.java | 39 +++++++- server/src/com/vaadin/server/VaadinService.java | 15 ++- .../com/vaadin/tests/event/EventRouterTest.java | 111 +++++++++++++++++++++ 3 files changed, 162 insertions(+), 3 deletions(-) create mode 100644 server/tests/src/com/vaadin/tests/event/EventRouterTest.java diff --git a/server/src/com/vaadin/event/EventRouter.java b/server/src/com/vaadin/event/EventRouter.java index 73bfa33881..fdc543143b 100644 --- a/server/src/com/vaadin/event/EventRouter.java +++ b/server/src/com/vaadin/event/EventRouter.java @@ -23,6 +23,10 @@ import java.util.EventObject; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; +import java.util.logging.Logger; + +import com.vaadin.server.ErrorEvent; +import com.vaadin.server.ErrorHandler; /** * EventRouter class implementing the inheritable event listening @@ -154,6 +158,25 @@ public class EventRouter implements MethodEventSource { * the Event to be sent to all listeners. */ public void fireEvent(EventObject event) { + fireEvent(event, null); + } + + /** + * Sends an event to all registered listeners. The listeners will decide if + * the activation method should be called or not. + *

+ * If an error handler is set, the processing of other listeners will + * continue after the error handler method call unless the error handler + * itself throws an exception. + * + * @param event + * the Event to be sent to all listeners. + * @param errorHandler + * error handler to use to handle any exceptions thrown by + * listeners or null to let the exception propagate to the + * caller, preventing further listener calls + */ + public void fireEvent(EventObject event, ErrorHandler errorHandler) { // It is not necessary to send any events if there are no listeners if (listenerList != null) { @@ -164,7 +187,16 @@ public class EventRouter implements MethodEventSource { // will filter out unwanted events. final Object[] listeners = listenerList.toArray(); for (int i = 0; i < listeners.length; i++) { - ((ListenerMethod) listeners[i]).receiveEvent(event); + ListenerMethod listenerMethod = (ListenerMethod) listeners[i]; + if (null != errorHandler) { + try { + listenerMethod.receiveEvent(event); + } catch (Exception e) { + errorHandler.error(new ErrorEvent(e)); + } + } else { + listenerMethod.receiveEvent(event); + } } } @@ -208,4 +240,9 @@ public class EventRouter implements MethodEventSource { } return listeners; } + + private Logger getLogger() { + return Logger.getLogger(EventRouter.class.getName()); + } + } diff --git a/server/src/com/vaadin/server/VaadinService.java b/server/src/com/vaadin/server/VaadinService.java index 44ceaaaf87..216adce3c8 100644 --- a/server/src/com/vaadin/server/VaadinService.java +++ b/server/src/com/vaadin/server/VaadinService.java @@ -414,6 +414,9 @@ public abstract class VaadinService implements Serializable { /** * Adds a listener that gets notified when a Vaadin service session that has * been initialized for this service is destroyed. + *

+ * The session being destroyed is locked and its UIs have been removed when + * the listeners are called. * * @see #addSessionInitListener(SessionInitListener) * @@ -455,8 +458,11 @@ public abstract class VaadinService implements Serializable { } }); } + // for now, use the session error handler; in the future, could + // have an API for using some other handler for session init and + // destroy listeners eventRouter.fireEvent(new SessionDestroyEvent( - VaadinService.this, session)); + VaadinService.this, session), session.getErrorHandler()); } }); } @@ -770,7 +776,12 @@ public abstract class VaadinService implements Serializable { private void onVaadinSessionStarted(VaadinRequest request, VaadinSession session) throws ServiceException { - eventRouter.fireEvent(new SessionInitEvent(this, session, request)); + // for now, use the session error handler; in the future, could have an + // API for using some other handler for session init and destroy + // listeners + + eventRouter.fireEvent(new SessionInitEvent(this, session, request), + session.getErrorHandler()); ServletPortletHelper.checkUiProviders(session, this); } diff --git a/server/tests/src/com/vaadin/tests/event/EventRouterTest.java b/server/tests/src/com/vaadin/tests/event/EventRouterTest.java new file mode 100644 index 0000000000..dbbeaf778e --- /dev/null +++ b/server/tests/src/com/vaadin/tests/event/EventRouterTest.java @@ -0,0 +1,111 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * 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 com.vaadin.tests.event; + +import java.lang.reflect.Method; + +import org.easymock.EasyMock; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.vaadin.event.EventRouter; +import com.vaadin.server.ErrorEvent; +import com.vaadin.server.ErrorHandler; +import com.vaadin.ui.Component; +import com.vaadin.ui.Component.Listener; +import com.vaadin.util.ReflectTools; + +/** + * Test EventRouter and related error handling. + */ +public class EventRouterTest { + + private static final Method COMPONENT_EVENT_METHOD = ReflectTools + .findMethod(Component.Listener.class, "componentEvent", + Component.Event.class); + + private EventRouter router; + private Component component; + private ErrorHandler errorHandler; + private Listener listener; + + @Before + public void createMocks() { + router = new EventRouter(); + component = EasyMock.createNiceMock(Component.class); + errorHandler = EasyMock.createMock(ErrorHandler.class); + listener = EasyMock.createMock(Component.Listener.class); + router.addListener(Component.Event.class, listener, + COMPONENT_EVENT_METHOD); + } + + @Test + public void fireEvent_noException_eventReceived() { + listener.componentEvent(EasyMock. anyObject()); + + EasyMock.replay(component, listener, errorHandler); + router.fireEvent(new Component.Event(component), errorHandler); + EasyMock.verify(listener, errorHandler); + } + + @Test + public void fireEvent_exceptionFromListenerAndNoHandler_exceptionPropagated() { + listener.componentEvent(EasyMock. anyObject()); + EasyMock.expectLastCall().andThrow( + new RuntimeException("listener failed")); + + EasyMock.replay(component, listener); + try { + router.fireEvent(new Component.Event(component)); + Assert.fail("Did not receive expected exception from listener"); + } catch (RuntimeException e) { + // e is a ListenerMethod@MethodException + Assert.assertEquals("listener failed", e.getCause().getMessage()); + } + EasyMock.verify(listener); + } + + @Test + public void fireEvent_exceptionFromListener_errorHandlerCalled() { + listener.componentEvent(EasyMock. anyObject()); + EasyMock.expectLastCall().andThrow( + new RuntimeException("listener failed")); + errorHandler.error(EasyMock. anyObject()); + + EasyMock.replay(component, listener, errorHandler); + router.fireEvent(new Component.Event(component), errorHandler); + EasyMock.verify(listener, errorHandler); + } + + @Test + public void fireEvent_multipleListenersAndException_errorHandlerCalled() { + Listener listener2 = EasyMock.createMock(Component.Listener.class); + router.addListener(Component.Event.class, listener2, + COMPONENT_EVENT_METHOD); + + listener.componentEvent(EasyMock. anyObject()); + EasyMock.expectLastCall().andThrow( + new RuntimeException("listener failed")); + errorHandler.error(EasyMock. anyObject()); + // second listener should be called despite an error in the first + listener2.componentEvent(EasyMock. anyObject()); + + EasyMock.replay(component, listener, listener2, errorHandler); + router.fireEvent(new Component.Event(component), errorHandler); + EasyMock.verify(listener, listener2, errorHandler); + } +} -- cgit v1.2.3 From 8abf43431ea67f7c3d7cc4faad816e2cddd4ac1d Mon Sep 17 00:00:00 2001 From: Mika Murtojarvi Date: Wed, 27 Nov 2013 09:26:07 +0200 Subject: Move working sass tests from sasslangbroken to sasslang. Change-Id: Ic503021884fd52b650f29df221cef3e69e8ef570 --- theme-compiler/tests/resources/sasslang/css/350-test_interpolation.css | 3 +++ .../sasslang/css/390-test_parent_selector_with_parent_and_subject.css | 3 +++ .../tests/resources/sasslang/scss/350-test_interpolation.scss | 2 ++ .../scss/390-test_parent_selector_with_parent_and_subject.scss | 3 +++ .../tests/resources/sasslangbroken/css/350-test_interpolation.css | 3 --- .../css/390-test_parent_selector_with_parent_and_subject.css | 3 --- .../tests/resources/sasslangbroken/scss/350-test_interpolation.scss | 2 -- .../scss/390-test_parent_selector_with_parent_and_subject.scss | 3 --- 8 files changed, 11 insertions(+), 11 deletions(-) create mode 100644 theme-compiler/tests/resources/sasslang/css/350-test_interpolation.css create mode 100644 theme-compiler/tests/resources/sasslang/css/390-test_parent_selector_with_parent_and_subject.css create mode 100644 theme-compiler/tests/resources/sasslang/scss/350-test_interpolation.scss create mode 100644 theme-compiler/tests/resources/sasslang/scss/390-test_parent_selector_with_parent_and_subject.scss delete mode 100644 theme-compiler/tests/resources/sasslangbroken/css/350-test_interpolation.css delete mode 100644 theme-compiler/tests/resources/sasslangbroken/css/390-test_parent_selector_with_parent_and_subject.css delete mode 100644 theme-compiler/tests/resources/sasslangbroken/scss/350-test_interpolation.scss delete mode 100644 theme-compiler/tests/resources/sasslangbroken/scss/390-test_parent_selector_with_parent_and_subject.scss diff --git a/theme-compiler/tests/resources/sasslang/css/350-test_interpolation.css b/theme-compiler/tests/resources/sasslang/css/350-test_interpolation.css new file mode 100644 index 0000000000..8b44646800 --- /dev/null +++ b/theme-compiler/tests/resources/sasslang/css/350-test_interpolation.css @@ -0,0 +1,3 @@ +ul li#foo a span.label { + foo: bar; +} diff --git a/theme-compiler/tests/resources/sasslang/css/390-test_parent_selector_with_parent_and_subject.css b/theme-compiler/tests/resources/sasslang/css/390-test_parent_selector_with_parent_and_subject.css new file mode 100644 index 0000000000..234fea7aa5 --- /dev/null +++ b/theme-compiler/tests/resources/sasslang/css/390-test_parent_selector_with_parent_and_subject.css @@ -0,0 +1,3 @@ +bar foo.baz! .bip { + c: d; +} diff --git a/theme-compiler/tests/resources/sasslang/scss/350-test_interpolation.scss b/theme-compiler/tests/resources/sasslang/scss/350-test_interpolation.scss new file mode 100644 index 0000000000..bb9c9a2c8f --- /dev/null +++ b/theme-compiler/tests/resources/sasslang/scss/350-test_interpolation.scss @@ -0,0 +1,2 @@ +$bar : "#foo"; +ul li#{$bar} a span.label { foo: bar; } diff --git a/theme-compiler/tests/resources/sasslang/scss/390-test_parent_selector_with_parent_and_subject.scss b/theme-compiler/tests/resources/sasslang/scss/390-test_parent_selector_with_parent_and_subject.scss new file mode 100644 index 0000000000..646238f379 --- /dev/null +++ b/theme-compiler/tests/resources/sasslang/scss/390-test_parent_selector_with_parent_and_subject.scss @@ -0,0 +1,3 @@ +$subject: "!"; +foo { + bar &.baz#{$subject} .bip {c: d}} diff --git a/theme-compiler/tests/resources/sasslangbroken/css/350-test_interpolation.css b/theme-compiler/tests/resources/sasslangbroken/css/350-test_interpolation.css deleted file mode 100644 index 8b44646800..0000000000 --- a/theme-compiler/tests/resources/sasslangbroken/css/350-test_interpolation.css +++ /dev/null @@ -1,3 +0,0 @@ -ul li#foo a span.label { - foo: bar; -} diff --git a/theme-compiler/tests/resources/sasslangbroken/css/390-test_parent_selector_with_parent_and_subject.css b/theme-compiler/tests/resources/sasslangbroken/css/390-test_parent_selector_with_parent_and_subject.css deleted file mode 100644 index 234fea7aa5..0000000000 --- a/theme-compiler/tests/resources/sasslangbroken/css/390-test_parent_selector_with_parent_and_subject.css +++ /dev/null @@ -1,3 +0,0 @@ -bar foo.baz! .bip { - c: d; -} diff --git a/theme-compiler/tests/resources/sasslangbroken/scss/350-test_interpolation.scss b/theme-compiler/tests/resources/sasslangbroken/scss/350-test_interpolation.scss deleted file mode 100644 index bb9c9a2c8f..0000000000 --- a/theme-compiler/tests/resources/sasslangbroken/scss/350-test_interpolation.scss +++ /dev/null @@ -1,2 +0,0 @@ -$bar : "#foo"; -ul li#{$bar} a span.label { foo: bar; } diff --git a/theme-compiler/tests/resources/sasslangbroken/scss/390-test_parent_selector_with_parent_and_subject.scss b/theme-compiler/tests/resources/sasslangbroken/scss/390-test_parent_selector_with_parent_and_subject.scss deleted file mode 100644 index 646238f379..0000000000 --- a/theme-compiler/tests/resources/sasslangbroken/scss/390-test_parent_selector_with_parent_and_subject.scss +++ /dev/null @@ -1,3 +0,0 @@ -$subject: "!"; -foo { - bar &.baz#{$subject} .bip {c: d}} -- cgit v1.2.3 From 1ac492e46b70de9314083492bd8e136e1c8398e3 Mon Sep 17 00:00:00 2001 From: Mika Murtojarvi Date: Wed, 27 Nov 2013 13:29:51 +0200 Subject: Move a sass test that no longer fails. Change-Id: Ic83330cbea688be1c30aa89cad9524016617be8d --- .../tests/resources/sasslang/css/369-test_mixins_with_empty_args.css | 3 +++ .../tests/resources/sasslang/scss/369-test_mixins_with_empty_args.scss | 3 +++ .../resources/sasslangbroken/css/369-test_mixins_with_empty_args.css | 3 --- .../resources/sasslangbroken/scss/369-test_mixins_with_empty_args.scss | 3 --- 4 files changed, 6 insertions(+), 6 deletions(-) create mode 100644 theme-compiler/tests/resources/sasslang/css/369-test_mixins_with_empty_args.css create mode 100644 theme-compiler/tests/resources/sasslang/scss/369-test_mixins_with_empty_args.scss delete mode 100644 theme-compiler/tests/resources/sasslangbroken/css/369-test_mixins_with_empty_args.css delete mode 100644 theme-compiler/tests/resources/sasslangbroken/scss/369-test_mixins_with_empty_args.scss diff --git a/theme-compiler/tests/resources/sasslang/css/369-test_mixins_with_empty_args.css b/theme-compiler/tests/resources/sasslang/css/369-test_mixins_with_empty_args.css new file mode 100644 index 0000000000..234d524066 --- /dev/null +++ b/theme-compiler/tests/resources/sasslang/css/369-test_mixins_with_empty_args.css @@ -0,0 +1,3 @@ +.foo { + a: b; +} diff --git a/theme-compiler/tests/resources/sasslang/scss/369-test_mixins_with_empty_args.scss b/theme-compiler/tests/resources/sasslang/scss/369-test_mixins_with_empty_args.scss new file mode 100644 index 0000000000..f608979293 --- /dev/null +++ b/theme-compiler/tests/resources/sasslang/scss/369-test_mixins_with_empty_args.scss @@ -0,0 +1,3 @@ +@mixin foo() {a: b} + +.foo {@include foo();} diff --git a/theme-compiler/tests/resources/sasslangbroken/css/369-test_mixins_with_empty_args.css b/theme-compiler/tests/resources/sasslangbroken/css/369-test_mixins_with_empty_args.css deleted file mode 100644 index 234d524066..0000000000 --- a/theme-compiler/tests/resources/sasslangbroken/css/369-test_mixins_with_empty_args.css +++ /dev/null @@ -1,3 +0,0 @@ -.foo { - a: b; -} diff --git a/theme-compiler/tests/resources/sasslangbroken/scss/369-test_mixins_with_empty_args.scss b/theme-compiler/tests/resources/sasslangbroken/scss/369-test_mixins_with_empty_args.scss deleted file mode 100644 index f608979293..0000000000 --- a/theme-compiler/tests/resources/sasslangbroken/scss/369-test_mixins_with_empty_args.scss +++ /dev/null @@ -1,3 +0,0 @@ -@mixin foo() {a: b} - -.foo {@include foo();} -- cgit v1.2.3