diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AbstractAsyncCallback.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AbstractAsyncCallback.java
index 03c3eeaef8404f0af031617abfd0fe87a06e1345..5a46195772b797be4cbd4338e0cfe6a2b58112b4 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AbstractAsyncCallback.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AbstractAsyncCallback.java
@@ -277,21 +277,20 @@ public abstract class AbstractAsyncCallback<T> implements AsyncCallback<T>
     }
 
     /**
-     * This method should be called if callback will not be processed, to make our system test
-     * framework working properly.
+     * This method should be called if callback will not be processed immediately after creation. It
+     * is needed for our system test framework to work properly.
      */
     public final void ignore()
     {
-        // could do this only if staticCallbackListener != DEFAULT_CALLBACK_LISTENER
         callbackListener.ignoreCallback(this);
     }
 
     /**
-     * This method should be called at the beginning of process method if we want to have a reusable
-     * callback that is working properly with our test framework. First ignore should be called in
-     * callback constructor after calling abstract constructor.
+     * This method should be called for callbacks that are reusable. Call it just before calling
+     * service method but make sure {@link #ignore()} was called first in callback constructor after
+     * calling abstract constructor. It is needed for our system test framework to work properly.
      */
-    protected final void reuse()
+    public final void reuse()
     {
         callbackListener.registerCallback(this);
     }
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AuthenticationTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AuthenticationTest.java
index a0f3d1033c54c0ec4f7e8bdc6c6735e1173b06e2..cd1f56cb8d66a22d4d862b838ceba83913b00706 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AuthenticationTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AuthenticationTest.java
@@ -21,7 +21,7 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.LoginWi
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.Logout;
 import ch.systemsx.cisd.openbis.generic.client.web.client.testframework.AbstractGWTTestCase;
 import ch.systemsx.cisd.openbis.generic.client.web.client.testframework.FailureExpectation;
-import ch.systemsx.cisd.openbis.generic.client.web.client.testframework.WaitFor;
+import ch.systemsx.cisd.openbis.generic.client.web.client.testframework.WaitForAllActiveCallbacksFinish;
 
 /**
  * A {@link AbstractGWTTestCase} extension to test login.
@@ -33,7 +33,7 @@ public class AuthenticationTest extends AbstractGWTTestCase
     public void testLogin() throws Exception
     {
         remoteConsole.prepare(new Login("test", "a"));
-        remoteConsole.prepare(new WaitFor(LoginWidget.LoginCallback.class));
+        remoteConsole.prepare(new WaitForAllActiveCallbacksFinish());
 
         launchTest(30000);
     }
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/Login.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/Login.java
index 0b453cb28007ca06d22628f355c1638107018644..054f3e717ac1be753379ffe360fa417a1fb72603 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/Login.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/Login.java
@@ -18,13 +18,12 @@ package ch.systemsx.cisd.openbis.generic.client.web.client.application.ui;
 
 import com.extjs.gxt.ui.client.widget.form.TextField;
 
-import ch.systemsx.cisd.openbis.generic.client.web.client.application.SessionContextCallback;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.StringUtils;
 import ch.systemsx.cisd.openbis.generic.client.web.client.testframework.AbstractDefaultTestCommand;
 import ch.systemsx.cisd.openbis.generic.client.web.client.testframework.GWTTestUtil;
 
 /**
- * Command for login after {@link SessionContextCallback} has finished.
+ * Command for login.
  * 
  * @author Franz-Josef Elmer
  */
@@ -36,7 +35,6 @@ public class Login extends AbstractDefaultTestCommand
 
     public Login(final String user, final String password)
     {
-        super(SessionContextCallback.class);
         this.user = user;
         this.password = password;
     }
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/Logout.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/Logout.java
index 3eb9a01c4a79daa46519940a25a17f51b6b04cff..f0e48c30787135c1b926b7bed05a8e761cd0bab1 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/Logout.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/Logout.java
@@ -16,13 +16,12 @@
 
 package ch.systemsx.cisd.openbis.generic.client.web.client.application.ui;
 
-import ch.systemsx.cisd.openbis.generic.client.web.client.application.SessionContextCallback;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.menu.TopMenu.ActionMenuKind;
 import ch.systemsx.cisd.openbis.generic.client.web.client.testframework.AbstractDefaultTestCommand;
 import ch.systemsx.cisd.openbis.generic.client.web.client.testframework.GWTTestUtil;
 
 /**
- * Command for logout after {@link SessionContextCallback} has finished.
+ * Command for logout.
  * 
  * @author Franz-Josef Elmer
  * @author Piotr Buczek
@@ -32,12 +31,10 @@ public class Logout extends AbstractDefaultTestCommand
     public Logout(String callbackClassId)
     {
         super();
-        addCallbackClass(callbackClassId);
     }
 
     public Logout()
     {
-        super(SessionContextCallback.class);
     }
 
     public void execute()
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/AbstractDefaultTestCommand.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/AbstractDefaultTestCommand.java
index dbaab5d212b53e890491a68b0f14ccf9eff39758..1cddfb1e9ea8b5759171861b39d6fd141c3ee881 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/AbstractDefaultTestCommand.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/AbstractDefaultTestCommand.java
@@ -23,6 +23,8 @@ import junit.framework.Assert;
 
 import com.google.gwt.user.client.rpc.AsyncCallback;
 
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.AbstractAsyncCallback;
+
 /**
  * Abstract super class of all test commands which are executed if there are no active callbacks
  * (all callbacks were detected by {@link RemoteConsole}).
@@ -81,7 +83,8 @@ public abstract class AbstractDefaultTestCommand extends Assert implements ITest
         return true; // if previous command succeeded this command should be executed
     }
 
-    public boolean isValidOnFailure(final String failureMessage, final Throwable throwable)
+    public boolean isValidOnFailure(AbstractAsyncCallback<?> callback, String failureMessage,
+            Throwable throwable)
     {
         return false; // if previous command failed this command shouldn't be executed
     }
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/FailureExpectation.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/FailureExpectation.java
index a3873909a65c2ce8f230c12b53cce1a1a8a3c99f..f7b60ab4e9ac65dce2e97c269f2f340fdf7aa0a4 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/FailureExpectation.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/FailureExpectation.java
@@ -18,6 +18,8 @@ package ch.systemsx.cisd.openbis.generic.client.web.client.testframework;
 
 import com.google.gwt.user.client.rpc.AsyncCallback;
 
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.AbstractAsyncCallback;
+
 /**
  * Failure expectation.
  * 
@@ -34,11 +36,19 @@ public class FailureExpectation extends AbstractDefaultTestCommand
             }
         };
 
+    private Class<? extends AsyncCallback<?>> expectedCallbackClassOrNull;
+
     private Class<? extends Throwable> expectedThrowableClassOrNull;
 
+    /** command will expect any callback failure */
+    public FailureExpectation()
+    {
+    }
+
+    /** command will expect failure of a callback of specified <var>callbackClass</var> */
     public FailureExpectation(Class<? extends AsyncCallback<?>> callbackClass)
     {
-        super(callbackClass);
+        this.expectedCallbackClassOrNull = callbackClass;
     }
 
     public FailureExpectation with(final String failureMessage)
@@ -71,8 +81,13 @@ public class FailureExpectation extends AbstractDefaultTestCommand
     }
 
     @Override
-    public boolean isValidOnFailure(String failureMessage, Throwable throwable)
+    public boolean isValidOnFailure(AbstractAsyncCallback<?> callback, String failureMessage,
+            Throwable throwable)
     {
+        if (expectedCallbackClassOrNull != null)
+        {
+            assertEquals(expectedCallbackClassOrNull, callback.getClass());
+        }
         messageValidator.assertValid(failureMessage);
         if (expectedThrowableClassOrNull == null
                 || expectedThrowableClassOrNull.equals(throwable.getClass()))
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/ITestCommand.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/ITestCommand.java
index 7fc1d6de836bb7e1dee9851d2051142feaa6f71d..01c8d0eb3fb7ae86a27449e8240c01584997e773 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/ITestCommand.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/ITestCommand.java
@@ -18,6 +18,8 @@ package ch.systemsx.cisd.openbis.generic.client.web.client.testframework;
 
 import com.google.gwt.user.client.rpc.AsyncCallback;
 
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.AbstractAsyncCallback;
+
 /**
  * A command which will be executed after a successful invocation of
  * {@link AsyncCallback#onSuccess(Object)}.
@@ -41,8 +43,10 @@ public interface ITestCommand
     /**
      * @return <tt>true</tt> if the specified <var>failureMessage</var> and <var>throwable</var>
      *         should trigger this command in case of an invocation of
-     *         {@link AsyncCallback#onFailure(Throwable)}, otherwise <tt>false</tt>
+     *         {@link AsyncCallback#onFailure(Throwable)} of specified <var>callback</var>,
+     *         otherwise <tt>false</tt>
      */
-    public boolean isValidOnFailure(String failureMessage, Throwable throwable);
+    public boolean isValidOnFailure(AbstractAsyncCallback<?> callback, String failureMessage,
+            Throwable throwable);
 
 }
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/RemoteConsole.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/RemoteConsole.java
index 45959282cfbb5f38ac8e4f9b412e50837fc48cbf..a7a24bcd34d4ff2e6c2e2a46db9bf5742a809a76 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/RemoteConsole.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/RemoteConsole.java
@@ -166,7 +166,7 @@ public class RemoteConsole
                 ITestCommand cmd = commands.get(entryIndex);
                 // It doesn't need to be the last callbacks that fails,
                 // and it should rather be the last command.
-                if (cmd.isValidOnFailure(failureMessage, throwable))
+                if (cmd.isValidOnFailure(callback, failureMessage, throwable))
                 {
                     executeCommand();
                     return;
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/WaitFor.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/WaitForAllActiveCallbacksFinish.java
similarity index 68%
rename from openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/WaitFor.java
rename to openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/WaitForAllActiveCallbacksFinish.java
index 3ede6c5d9b7b392b7bb20bfef57c4b71d1f3e78a..1883eb3a6059d92fa19ab184d8778f7feef9390f 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/WaitFor.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/WaitForAllActiveCallbacksFinish.java
@@ -16,29 +16,21 @@
 
 package ch.systemsx.cisd.openbis.generic.client.web.client.testframework;
 
-import com.google.gwt.user.client.rpc.AsyncCallback;
-
 /**
+ * {@link AbstractDefaultTestCommand} extension that does nothing. It should be used if we want to
+ * make sure that all callbacks will finish without failure.
  * 
- *
- * @author Franz-Josef Elmer
+ * @author Piotr Buczek
  */
-public class WaitFor extends AbstractDefaultTestCommand
+public class WaitForAllActiveCallbacksFinish extends AbstractDefaultTestCommand
 {
-    public WaitFor(Class<? extends AsyncCallback<?>> callbackClass)
+    public WaitForAllActiveCallbacksFinish()
     {
-        super(callbackClass);
+        super();
     }
 
     public void execute()
     {
     }
 
-    @Override
-    public String toString()
-    {
-        return "Wait for " + expectedCallbackIds;
-    }
-
-    
 }
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/experiment/GenericExperimentAttachmentDownloadTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/experiment/GenericExperimentAttachmentDownloadTest.java
index d404ffa6cc4f84a48a552c9f8d3b44a8cfdc2764..7f8a4b70bf008caf10ab63864321f8236269bef7 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/experiment/GenericExperimentAttachmentDownloadTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/experiment/GenericExperimentAttachmentDownloadTest.java
@@ -95,7 +95,6 @@ public class GenericExperimentAttachmentDownloadTest extends AbstractGWTTestCase
         @Override
         protected void process(String url)
         {
-            reuse();
             this.openedUrl = url;
         }
 
@@ -190,6 +189,7 @@ public class GenericExperimentAttachmentDownloadTest extends AbstractGWTTestCase
             {
                 case AppEvents.OPEN_URL_EVENT:
                     String openedUrl = (String) event.data;
+                    openedUrlCallback.reuse();
                     openedUrlCallback.onSuccess(openedUrl);
                     break;
                 default: