diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AbstractGWTTestCase.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AbstractGWTTestCase.java new file mode 100644 index 0000000000000000000000000000000000000000..8f219f072dd0d3c43358a93827fa2a0c4fee7323 --- /dev/null +++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AbstractGWTTestCase.java @@ -0,0 +1,52 @@ +/* + * Copyright 2008 ETH Zuerich, CISD + * + * 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 ch.systemsx.cisd.openbis.generic.client.web.client.application; + +import com.google.gwt.junit.client.GWTTestCase; + +/** + * Abstract super class of all GWT System Tests. + * + * @author Franz-Josef Elmer + */ +public abstract class AbstractGWTTestCase extends GWTTestCase +{ + + @Override + public String getModuleName() + { + return "ch.systemsx.cisd.openbis.OpenBIS"; + } + + /** + * Terminates test. Wrapper of {@link #finishTest()}. Will be used in {@link RemoteConsole}. + */ + void terminateTest() + { + finishTest(); + } + + /** + * Delays test termination until the specified timeout (in milliseconds). Wrapper of + * {@link #delayTestFinish(int)}. Will be used in {@link RemoteConsole}. + */ + void delayTestTermination(int timeoutMillis) + { + delayTestFinish(timeoutMillis); + } + +} diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/CallbackClassCondition.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/CallbackClassCondition.java new file mode 100644 index 0000000000000000000000000000000000000000..c097ee417321866b6ceecfb7444f0347dba3ca01 --- /dev/null +++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/CallbackClassCondition.java @@ -0,0 +1,43 @@ +/* + * Copyright 2008 ETH Zuerich, CISD + * + * 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 ch.systemsx.cisd.openbis.generic.client.web.client.application; + +import com.google.gwt.user.client.rpc.AsyncCallback; + +/** + * Contition which checks whether the class of the callback object is as specified. + * + * @author Franz-Josef Elmer + */ +public class CallbackClassCondition implements ICallbackCondition<Object> +{ + private final Class<?> callbackClass; + + /** + * Creates an instance for the specified callback class. + */ + public CallbackClassCondition(Class<? extends AsyncCallback<?>> callbackClass) + { + this.callbackClass = callbackClass; + } + + public boolean valid(AsyncCallback<Object> callback, Object result) + { + return callbackClass.equals(callback.getClass()); + } + +} diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ClientTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ClientTest.java new file mode 100644 index 0000000000000000000000000000000000000000..01dac981b8174050b07136a494b3c966688cf827 --- /dev/null +++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ClientTest.java @@ -0,0 +1,54 @@ +/* + * Copyright 2008 ETH Zuerich, CISD + * + * 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 ch.systemsx.cisd.openbis.generic.client.web.client.application; + + +import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.LoginCommand; + + +/** + * + * + * @author Franz-Josef Elmer + */ +public class ClientTest extends AbstractGWTTestCase +{ + + private RemoteConsole remoteConsole; + + + @Override + protected void gwtSetUp() throws Exception + { + remoteConsole = new RemoteConsole(this); + } + + public void testLogin() throws Exception + { + final Client client = new Client(); + client.onModuleLoad(); + remoteConsole.prepare(new LoginCommand("test", "blabla")).finish(10000); + } + + public void testFailedLogin() throws Exception + { + final Client client = new Client(); + client.onModuleLoad(); + remoteConsole.prepare(new LoginCommand("", "")).finish(10000); + } + +} diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/GWTTestUtil.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/GWTTestUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..76f84468496bb64d6baba414d577a73c3aa8eb7f --- /dev/null +++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/GWTTestUtil.java @@ -0,0 +1,130 @@ +/* + * Copyright 2008 ETH Zuerich, CISD + * + * 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 ch.systemsx.cisd.openbis.generic.client.web.client.application; + +import java.util.List; + +import junit.framework.Assert; + +import com.extjs.gxt.ui.client.widget.Component; +import com.extjs.gxt.ui.client.widget.Container; +import com.extjs.gxt.ui.client.widget.ContentPanel; +import com.extjs.gxt.ui.client.widget.button.Button; +import com.extjs.gxt.ui.client.widget.form.TextField; +import com.google.gwt.user.client.ui.ComplexPanel; +import com.google.gwt.user.client.ui.RootPanel; +import com.google.gwt.user.client.ui.Widget; + +/** + * Useful static methods for testing. + * + * @author Franz-Josef Elmer + */ +public class GWTTestUtil +{ + private GWTTestUtil() + { + } + + /** + * Gets the {@link Button} with specified id. + * + * @throws AssertionError if not found or isn't a text field. + */ + public static Button getButtonWithID(String id) + { + Widget widget = tryToFindByID(id); + Assert.assertNotNull("Button '" + id + "' not found.", widget); + Assert.assertTrue("Widget '" + id + "' isn't a Button: " + widget.getClass(), + widget instanceof Button); + return (Button) widget; + } + + /** + * Gets the {@link TextField} with specified id. + * + * @throws AssertionError if not found or isn't a text field. + */ + @SuppressWarnings("unchecked") + public static <T> TextField<T> getTextFieldWithID(String id) + { + Widget widget = tryToFindByID(id); + Assert.assertNotNull("Text field '" + id + "' not found.", widget); + Assert.assertTrue("Widget '" + id + "' isn't a TextField: " + widget.getClass(), + widget instanceof TextField); + return (TextField<T>) widget; + } + + /** + * Tries to find the Widget of specified type with specified id. + */ + @SuppressWarnings("unchecked") + public static <T extends Widget> T tryToFindByID(Class<T> widgetClass, String id) + { + return (T) tryToFindByID(id); + } + + /** + * Tries to find the widget with specified id. + * + * @return <code>null</code> if not found. + */ + public static Widget tryToFindByID(String id) + { + return tryToFindByID(RootPanel.get(), id); + } + + @SuppressWarnings("unchecked") + private static Widget tryToFindByID(Widget widget, String id) + { + Widget result = null; + if (id.equals(widget.getElement().getId())) + { + result = widget; + } else if ((widget instanceof Component) && id.equals(((Component) widget).getId())) + { + result = widget; + } else if (widget instanceof ComplexPanel) + { + ComplexPanel panel = (ComplexPanel) widget; + for (int i = 0, n = panel.getWidgetCount(); i < n && result == null; i++) + { + result = tryToFindByID(panel.getWidget(i), id); + } + } else if (widget instanceof Container) + { + Container<Component> container = (Container<Component>) widget; + List<Component> items = container.getItems(); + for (int i = 0, n = items.size(); i < n && result == null; i++) + { + result = tryToFindByID(items.get(i), id); + } + if (result == null && widget instanceof ContentPanel) + { + ContentPanel contentPanel = (ContentPanel) widget; + List<Button> buttons = contentPanel.getButtonBar().getItems(); + for (int i = 0, n = buttons.size(); i < n && result == null; i++) + { + result = tryToFindByID(buttons.get(i), id); + } + } + } + return result; + } + + +} diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ICallbackCondition.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ICallbackCondition.java new file mode 100644 index 0000000000000000000000000000000000000000..83f05b50bab0d3f2a033e8aec85916d93ea316cd --- /dev/null +++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ICallbackCondition.java @@ -0,0 +1,33 @@ +/* + * Copyright 2008 ETH Zuerich, CISD + * + * 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 ch.systemsx.cisd.openbis.generic.client.web.client.application; + +import com.google.gwt.user.client.rpc.AsyncCallback; + +/** + * Condition a callback object and/or the result delivered by the callback object have + * to fulfilled in order to execute a {@link ITestCommand} in {@link RemoteConsole}. + * + * @author Franz-Josef Elmer + */ +public interface ICallbackCondition<T> +{ + /** + * Returns <code>true</code> if the condition is fulfilled. + */ + public boolean valid(AsyncCallback<T> callback, T result); +} diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ITestCommand.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ITestCommand.java new file mode 100644 index 0000000000000000000000000000000000000000..d72a356f9f1737f73b00b2147d58808a26b43277 --- /dev/null +++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ITestCommand.java @@ -0,0 +1,33 @@ +/* + * Copyright 2008 ETH Zuerich, CISD + * + * 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 ch.systemsx.cisd.openbis.generic.client.web.client.application; + +import org.aopalliance.intercept.Invocation; + +/** + * A commad which will be executed after a successful {@link Invocation} of + * {@link AbstractAsyncCallback#process(Object)}. + * + * @author Franz-Josef Elmer + */ +public interface ITestCommand +{ + /** + * Executes this command. + */ + public void execute(); +} diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ITestCommandWithCondition.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ITestCommandWithCondition.java new file mode 100644 index 0000000000000000000000000000000000000000..96ec8b560d3107989da2859019236782a4d5a588 --- /dev/null +++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ITestCommandWithCondition.java @@ -0,0 +1,27 @@ +/* + * Copyright 2008 ETH Zuerich, CISD + * + * 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 ch.systemsx.cisd.openbis.generic.client.web.client.application; + +/** + * Interface of all test commands which knows also their condition for execution. + * + * @author Franz-Josef Elmer + */ +public interface ITestCommandWithCondition<T> extends ITestCommand, ICallbackCondition<T> +{ + +} diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/RemoteConsole.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/RemoteConsole.java new file mode 100644 index 0000000000000000000000000000000000000000..16e4f10770e684ca798d7c351a42b9d005647893 --- /dev/null +++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/RemoteConsole.java @@ -0,0 +1,168 @@ +/* + * Copyright 2008 ETH Zuerich, CISD + * + * 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 ch.systemsx.cisd.openbis.generic.client.web.client.application; + +import java.util.ArrayList; +import java.util.List; + +import junit.framework.Assert; + +import com.google.gwt.user.client.Timer; +import com.google.gwt.user.client.rpc.AsyncCallback; + +/** + * A class which allows to execute a sequence of {@link ITestCommand} instances. The commands are + * executed in the order they have been added by the various prepare methods. A + * {@link ICallbackCondition} has to be fulfilled before the next command is executed. This + * condition is checked after each successful invocation of + * {@link AbstractAsyncCallback#process(Object)}. With the method {@link #finish(int)} a timeout + * will be specified after which the test will be terminated independent whether all commands have + * been executed or not. In the later case the test fails. + * + * @author Franz-Josef Elmer + */ +public class RemoteConsole +{ + private static final class CommandEntry + { + private final ICallbackCondition<Object> condition; + private final ITestCommand command; + CommandEntry(ICallbackCondition<Object> condition, ITestCommand command) + { + this.condition = condition; + this.command = command; + } + } + + private class EqualsCallback implements ICallbackCondition<Object> + { + private final AsyncCallback<?> callbackToCheck; + + public EqualsCallback(AsyncCallback<?> callback) + { + this.callbackToCheck = callback; + } + + public boolean valid(AsyncCallback<Object> callback, Object result) + { + return callbackToCheck.equals(callback); + } + } + + private final AbstractGWTTestCase testCase; + private final List<CommandEntry> entries; + + private int entryIndex; + + /** + * Creates an instance for the specified test. + */ + public RemoteConsole(final AbstractGWTTestCase testCase) + { + this.testCase = testCase; + entries = new ArrayList<CommandEntry>(); + AbstractAsyncCallback.setCallbackListener(new ICallbackListener() + { + public void onFailureOf(AsyncCallback<Object> callback, Throwable throwable) + { + Assert.fail("Failed condition " + callback + ": " + throwable); + } + + public void startOnSuccessOf(AsyncCallback<Object> callback, Object result) + { + } + + public void finishOnSuccessOf(AsyncCallback<Object> callback, Object result) + { + System.out.println(entryIndex + "/" + entries.size() + ": " + callback); + if (entryIndex < entries.size() + && entries.get(entryIndex).condition.valid(callback, result)) + { + CommandEntry commandEntry = entries.get(entryIndex++); + commandEntry.command.execute(); + if (entryIndex == entries.size()) + { + testCase.terminateTest(); + } + } + } + + }); + } + + /** + * Prepares the console with the specified command. + */ + public RemoteConsole prepare(ITestCommandWithCondition<Object> command) + { + return prepare(command, command); + } + + /** + * Prepares the console with the specified command which will be executed if the + * class of the callback object is as specified. + */ + public RemoteConsole prepare(Class<? extends AsyncCallback<?>> clazz, ITestCommand command) + { + return prepare(new CallbackClassCondition(clazz), command); + } + + /** + * Prepares the console with the specified command which will be executed if the + * callback object equals the specified one. + */ + public RemoteConsole prepare(AsyncCallback<?> callback, ITestCommand command) + { + return prepare(new EqualsCallback(callback), command); + } + + /** + * Prepares the console with the specified command which will be executed if the + * specified condition is fulfilled. + */ + public RemoteConsole prepare(ICallbackCondition<Object> condition, ITestCommand command) + { + entries.add(new CommandEntry(condition, command)); + return this; + } + + /** + * Sets the timeout after which the test is terminated. + * + * @throws AssertionError if not all commands have been executed. + */ + public void finish(int delayInMilliseconds) + { + new Timer() + { + @Override + public void run() + { + AbstractAsyncCallback.setCallbackListener(null); + int numberOfUnexcutedCommands = entries.size() - entryIndex; + if (numberOfUnexcutedCommands > 0) + { + Assert.fail("Console not finished. Last " + + (numberOfUnexcutedCommands == 1 ? "command has" + : numberOfUnexcutedCommands + " commands have") + + " not been executed."); + } + } + }.schedule(delayInMilliseconds); + testCase.delayTestTermination(delayInMilliseconds + 1000); + } +} diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/LoginCommand.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/LoginCommand.java new file mode 100644 index 0000000000000000000000000000000000000000..fad38b60aba0424c46c6b1c20d225e4c5a3cffba --- /dev/null +++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/LoginCommand.java @@ -0,0 +1,51 @@ +/* + * Copyright 2008 ETH Zuerich, CISD + * + * 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 ch.systemsx.cisd.openbis.generic.client.web.client.application.ui; + +import com.extjs.gxt.ui.client.Events; + +import ch.systemsx.cisd.openbis.generic.client.web.client.application.CallbackClassCondition; +import ch.systemsx.cisd.openbis.generic.client.web.client.application.GWTTestUtil; +import ch.systemsx.cisd.openbis.generic.client.web.client.application.ITestCommandWithCondition; +import ch.systemsx.cisd.openbis.generic.client.web.client.application.SessionContextCallback; + +/** + * Command for login after {@link SessionContextCallback} has finished. + * + * @author Franz-Josef Elmer + */ +public class LoginCommand extends CallbackClassCondition implements ITestCommandWithCondition<Object> +{ + private final String user; + private final String password; + + public LoginCommand(String user, String password) + { + super(SessionContextCallback.class); + this.user = user; + this.password = password; + } + + @SuppressWarnings("unchecked") + public void execute() + { + GWTTestUtil.<String>getTextFieldWithID(LoginWidget.USER_FIELD_ID).setValue(user); + GWTTestUtil.<String>getTextFieldWithID(LoginWidget.PASSWORD_FIELD_ID).setValue(password); + GWTTestUtil.getButtonWithID(LoginWidget.BUTTON_ID).fireEvent(Events.Select); + } + +}