From fd327bb2256e0951d5bd8b5e89a0fcab1af657ff Mon Sep 17 00:00:00 2001 From: Tomas Kyjovsky Date: Tue, 9 Feb 2016 16:35:40 +0100 Subject: [PATCH 1/4] KEYCLOAK-1678 fixed cluster containers setup (-Djava.net.preferIPv4Stack=true is needed for cluster to form) --- .../base/src/test/resources/arquillian.xml | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml index 404f5b5fe3..fc91116cf8 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml +++ b/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml @@ -72,10 +72,12 @@ ${auth.server.wildfly.cluster} org.jboss.as.arquillian.container.managed.ManagedDeployableContainer ${keycloak.balancer.home} - + -Djboss.socket.binding.port-offset=${auth.server.port.offset} - -Xms64m -Xmx512m -XX:MaxPermSize=256m - ${adapter.test.props} + + + -Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m + -Djava.net.preferIPv4Stack=true ${auth.server.management.port} ${startup.timeout.sec} @@ -87,11 +89,14 @@ org.jboss.as.arquillian.container.managed.ManagedDeployableContainer ${keycloak.backend1.home} standalone-ha.xml - + -Djboss.socket.binding.port-offset=${auth.server.backend1.port.offset} - -Xms64m -Xmx512m -XX:MaxPermSize=256m - ${adapter.test.props} -Djboss.node.name=node1 + ${adapter.test.props} + + + -Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m + -Djava.net.preferIPv4Stack=true ${auth.server.backend1.management.port} @@ -104,11 +109,14 @@ org.jboss.as.arquillian.container.managed.ManagedDeployableContainer ${keycloak.backend2.home} standalone-ha.xml - + -Djboss.socket.binding.port-offset=${auth.server.backend2.port.offset} - -Xms64m -Xmx512m -XX:MaxPermSize=256m - ${adapter.test.props} -Djboss.node.name=node2 + ${adapter.test.props} + + + -Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m + -Djava.net.preferIPv4Stack=true ${auth.server.backend2.management.port} From 590ad1a7ca474bb7cb366f33ee4af64613ad512c Mon Sep 17 00:00:00 2001 From: Tomas Kyjovsky Date: Tue, 9 Feb 2016 16:36:00 +0100 Subject: [PATCH 2/4] KEYCLOAK-1678 fixed TwoNodeClusterTest --- .../cluster/AbstractClusterTest.java | 20 +++++++---- .../testsuite/cluster/TwoNodeClusterTest.java | 35 +++++++++++-------- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractClusterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractClusterTest.java index 9dd6089e06..29ba46234e 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractClusterTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractClusterTest.java @@ -35,25 +35,31 @@ public abstract class AbstractClusterTest extends AbstractKeycloakTest { controller.start(backendNode.getQualifier()); assertTrue(controller.isStarted(backendNode.getQualifier())); - log.info("Initializing admin client for: '" + backendNode.getContextRoot() + "/auth'"); - backendAdminClients.add(Keycloak.getInstance(backendNode.getContextRoot() + "/auth", - MASTER, ADMIN, ADMIN, Constants.ADMIN_CLI_CLIENT_ID)); + backendAdminClients.add(createAdminClientFor(backendNode)); } } + + protected Keycloak createAdminClientFor(ContainerInfo backendNode) { + log.info("Initializing admin client for " + backendNode.getContextRoot() + "/auth"); + return Keycloak.getInstance(backendNode.getContextRoot() + "/auth", + MASTER, ADMIN, ADMIN, Constants.ADMIN_CLI_CLIENT_ID); + } - protected ContainerInfo backendInfo(int i) { + protected ContainerInfo backendNode(int i) { return suiteContext.getAuthServerBackendsInfo().get(i); } protected void startBackendNode(int i) { - String container = backendInfo(i).getQualifier(); + String container = backendNode(i).getQualifier(); if (!controller.isStarted(container)) { controller.start(container); + backendAdminClients.set(i, createAdminClientFor(backendNode(i))); } } - protected void stopBackendNode(int i) { - controller.kill(backendInfo(i).getQualifier()); + protected void killBackendNode(int i) { + backendAdminClients.get(i).close(); + controller.kill(backendNode(i).getQualifier()); } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/TwoNodeClusterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/TwoNodeClusterTest.java index 0984124c0a..2732fdd1bc 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/TwoNodeClusterTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/TwoNodeClusterTest.java @@ -28,13 +28,13 @@ public class TwoNodeClusterTest extends AbstractClusterTest { } @Test - public void testRealm() { - testRealm(TEST, false); + public void testRealmCRUDWithoutFailover() { + testRealm(TEST + "_wofo", false); } @Test - public void testRealmWithFailover() { - testRealm(TEST + "_fo", true); + public void testRealmCRUDWithFailover() { + testRealm(TEST + "_wfo", true); } public void testRealm(String realm, boolean containerFailover) { @@ -43,9 +43,7 @@ public class TwoNodeClusterTest extends AbstractClusterTest { testRealm.setEnabled(true); // CREATE on node1 - log.info("Creating test realm via node1."); backend1AdminClient().realms().create(testRealm); - log.info("Test realm created."); // check if created on node1 RealmRepresentation testRealmOnBackend1 = backend1AdminClient().realms().realm(realm).toRepresentation(); @@ -60,29 +58,31 @@ public class TwoNodeClusterTest extends AbstractClusterTest { assertEquals(testRealmOnBackend1.getRealm(), testRealmOnBackend2.getRealm()); failback(); + pause(1000); // UPDATE on node2 - testRealmOnBackend2.setRealm(realm + "_updated"); + String realmUpdated = realm + "_updated"; + testRealmOnBackend2.setRealm(realmUpdated); backend2AdminClient().realms().realm(realm).update(testRealmOnBackend2); if (containerFailover) { stopBackend2(); } // check if updated on node1 - testRealmOnBackend1 = backend1AdminClient().realms().realm(realm).toRepresentation(); + testRealmOnBackend1 = backend1AdminClient().realms().realm(realmUpdated).toRepresentation(); assertEquals(testRealmOnBackend1.getId(), testRealmOnBackend2.getId()); assertEquals(testRealmOnBackend1.getRealm(), testRealmOnBackend2.getRealm()); failback(); // DELETE on node1 - backend1AdminClient().realms().realm(realm).remove(); + backend1AdminClient().realms().realm(realmUpdated).remove(); if (containerFailover) { stopBackend1(); } // check if deleted on node2 boolean testRealmOnBackend2Exists = false; for (RealmRepresentation realmOnBackend2 : backend2AdminClient().realms().findAll()) { - if (realm.equals(realmOnBackend2.getRealm()) + if (realmUpdated.equals(realmOnBackend2.getRealm()) || testRealmOnBackend1.getId().equals(realmOnBackend2.getId())) { testRealmOnBackend2Exists = true; break; @@ -91,12 +91,19 @@ public class TwoNodeClusterTest extends AbstractClusterTest { assertFalse(testRealmOnBackend2Exists); } + protected void listRealms(int i) { + log.info(String.format("Node %s: AccessTokenString: %s", i + 1, backendAdminClients.get(i).tokenManager().getAccessTokenString())); + for (RealmRepresentation r : backendAdminClients.get(i).realms().findAll()) { + log.info(String.format("Node %s: Realm: %s, Id: %s", i + 1, r.getRealm(), r.getId())); + } + } + protected ContainerInfo backend1Info() { - return backendInfo(0); + return backendNode(0); } protected ContainerInfo backend2Info() { - return backendInfo(1); + return backendNode(1); } protected Keycloak backend1AdminClient() { @@ -121,11 +128,11 @@ public class TwoNodeClusterTest extends AbstractClusterTest { } protected void stopBackend1() { - stopBackendNode(0); + killBackendNode(0); } protected void stopBackend2() { - stopBackendNode(1); + killBackendNode(1); } } From 620ca86d454ff19014bc6a2a10d62e10d2354411 Mon Sep 17 00:00:00 2001 From: Tomas Kyjovsky Date: Tue, 9 Feb 2016 19:29:03 +0100 Subject: [PATCH 3/4] KEYCLOAK-1678 updated README with some info about cluster tests --- testsuite/integration-arquillian/README.md | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/testsuite/integration-arquillian/README.md b/testsuite/integration-arquillian/README.md index 5f7f831649..39168de056 100644 --- a/testsuite/integration-arquillian/README.md +++ b/testsuite/integration-arquillian/README.md @@ -13,17 +13,28 @@ other options are: `auth-server-wildfly` and `auth-server-eap7`. The values corr **Note 1:** For the non-default options it's necessary to build a corresponding server module prior to running any of the test modules. This can be done by building the server module directly (from `servers/wildfly`/`servers/eap7`), or by activating `auth-server-wildfly`/`auth-server-eap7` profile when building from the top level module. -(The profiles will also set the proper value of the `auth.server.container` property.) **Note 2:** Most server-side configurations are done during the build of the server module and included in the output artifact - which is then consumed by the test modules( if a corresponding profile is activated). To reflect a change in server config in the test (e.g. a datasource) it's necessary to rebuild the server module after each change. -### Migration +#### Migration -Migration tests can be enabled by setting `-Dmigrated.auth.server.container` property or activating a corresponding profile. -When enabled, the `AuthServerTestEnricher` class will start/stop the selected *migrated* instance -even **before** the *current* auth server instance is started. +Migration tests can be enabled by setting `-Dmigrated.auth.server.version` property. Supported versions can be found at the bottom of `tests/pom.xml`. +When enabled, the `AuthServerTestEnricher` class will start and stop the selected migrated instance +*before* the current auth server instance is started. + +#### Cluster Setup + +Cluster setup can be enabled with profile `auth-server-wildfly-cluster`. +(It is also necessary to build the server modules with this profile before running the test. See *Notes 1 and 2* above.) + +Clustering tests require MULTICAST to be enabled on machine's `loopback` network interface. +This can be done by running the following commands under root privileges: +``` +route add -net 224.0.0.0 netmask 240.0.0.0 dev lo +ifconfig lo multicast +``` ### App Servers From ef77e2a246eec784fc824ae6e1dff143ebaa7302 Mon Sep 17 00:00:00 2001 From: Tomas Kyjovsky Date: Tue, 9 Feb 2016 19:30:02 +0100 Subject: [PATCH 4/4] KEYCLOAK-1678 added SessionFailoverClusterTest --- .../cluster/AbstractClusterTest.java | 14 ++- .../cluster/AbstractTwoNodeClusterTest.java | 57 +++++++++++ ...ava => EntityInvalidationClusterTest.java} | 89 ++++++----------- .../cluster/SessionFailoverClusterTest.java | 95 +++++++++++++++++++ 4 files changed, 194 insertions(+), 61 deletions(-) create mode 100644 testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractTwoNodeClusterTest.java rename testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/{TwoNodeClusterTest.java => EntityInvalidationClusterTest.java} (58%) create mode 100644 testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/SessionFailoverClusterTest.java diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractClusterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractClusterTest.java index 29ba46234e..fc523b7c62 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractClusterTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractClusterTest.java @@ -3,12 +3,15 @@ package org.keycloak.testsuite.cluster; import java.util.ArrayList; import java.util.List; import org.jboss.arquillian.container.test.api.ContainerController; +import org.jboss.arquillian.graphene.page.Page; import org.jboss.arquillian.test.api.ArquillianResource; import static org.junit.Assert.assertTrue; import org.keycloak.admin.client.Keycloak; import org.keycloak.models.Constants; +import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.testsuite.AbstractKeycloakTest; import org.keycloak.testsuite.arquillian.ContainerInfo; +import org.keycloak.testsuite.auth.page.AuthRealm; import static org.keycloak.testsuite.auth.page.AuthRealm.ADMIN; import static org.keycloak.testsuite.auth.page.AuthRealm.MASTER; @@ -38,11 +41,11 @@ public abstract class AbstractClusterTest extends AbstractKeycloakTest { backendAdminClients.add(createAdminClientFor(backendNode)); } } - + protected Keycloak createAdminClientFor(ContainerInfo backendNode) { log.info("Initializing admin client for " + backendNode.getContextRoot() + "/auth"); return Keycloak.getInstance(backendNode.getContextRoot() + "/auth", - MASTER, ADMIN, ADMIN, Constants.ADMIN_CLI_CLIENT_ID); + MASTER, ADMIN, ADMIN, Constants.ADMIN_CLI_CLIENT_ID); } protected ContainerInfo backendNode(int i) { @@ -62,4 +65,11 @@ public abstract class AbstractClusterTest extends AbstractKeycloakTest { controller.kill(backendNode(i).getQualifier()); } + protected void listRealms(int i) { + log.info(String.format("Node %s: AccessTokenString: %s", i + 1, backendAdminClients.get(i).tokenManager().getAccessTokenString())); + for (RealmRepresentation r : backendAdminClients.get(i).realms().findAll()) { + log.info(String.format("Node %s: Realm: %s, Id: %s", i + 1, r.getRealm(), r.getId())); + } + } + } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractTwoNodeClusterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractTwoNodeClusterTest.java new file mode 100644 index 0000000000..d88e616bbe --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractTwoNodeClusterTest.java @@ -0,0 +1,57 @@ +package org.keycloak.testsuite.cluster; + +import org.junit.Before; +import org.keycloak.admin.client.Keycloak; +import org.keycloak.testsuite.arquillian.ContainerInfo; +import static org.keycloak.testsuite.util.WaitUtils.pause; + +/** + * + * @author tkyjovsk + */ +public abstract class AbstractTwoNodeClusterTest extends AbstractClusterTest { + + @Before + public void beforeTwoNodeClusterTest() { + startBackendNodes(2); + pause(3000); + } + + protected ContainerInfo backend1Info() { + return backendNode(0); + } + + protected ContainerInfo backend2Info() { + return backendNode(1); + } + + protected Keycloak backend1AdminClient() { + return backendAdminClients.get(0); + } + + protected Keycloak backend2AdminClient() { + return backendAdminClients.get(1); + } + + protected void startBackend1() { + startBackendNode(0); + } + + protected void startBackend2() { + startBackendNode(1); + } + + protected void failback() { + startBackend1(); + startBackend2(); + } + + protected void killBackend1() { + killBackendNode(0); + } + + protected void killBackend2() { + killBackendNode(1); + } + +} diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/TwoNodeClusterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/EntityInvalidationClusterTest.java similarity index 58% rename from testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/TwoNodeClusterTest.java rename to testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/EntityInvalidationClusterTest.java index 2732fdd1bc..2175ed3697 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/TwoNodeClusterTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/EntityInvalidationClusterTest.java @@ -3,41 +3,31 @@ package org.keycloak.testsuite.cluster; import java.util.List; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import org.junit.Before; import org.junit.Test; -import org.keycloak.admin.client.Keycloak; import org.keycloak.representations.idm.RealmRepresentation; -import org.keycloak.testsuite.arquillian.ContainerInfo; import static org.keycloak.testsuite.auth.page.AuthRealm.TEST; -import static org.keycloak.testsuite.util.WaitUtils.pause; /** * * @author tkyjovsk */ -public class TwoNodeClusterTest extends AbstractClusterTest { +public class EntityInvalidationClusterTest extends AbstractTwoNodeClusterTest { @Override public void addTestRealms(List testRealms) { } - @Before - public void beforeTwoNodeClusterTest() { - startBackendNodes(2); - pause(3000); + @Test + public void realmCRUDWithoutFailover() { + realmCRUD(TEST + "_wofo", false); } @Test - public void testRealmCRUDWithoutFailover() { - testRealm(TEST + "_wofo", false); + public void realmCRUDWithFailover() { + realmCRUD(TEST + "_wfo", true); } - @Test - public void testRealmCRUDWithFailover() { - testRealm(TEST + "_wfo", true); - } - - public void testRealm(String realm, boolean containerFailover) { + public void realmCRUD(String realm, boolean containerFailover) { RealmRepresentation testRealm = new RealmRepresentation(); testRealm.setRealm(realm); testRealm.setEnabled(true); @@ -49,7 +39,7 @@ public class TwoNodeClusterTest extends AbstractClusterTest { RealmRepresentation testRealmOnBackend1 = backend1AdminClient().realms().realm(realm).toRepresentation(); assertEquals(testRealmOnBackend1.getRealm(), testRealm.getRealm()); if (containerFailover) { - stopBackend1(); + killBackend1(); } // check if created on node2 @@ -58,14 +48,13 @@ public class TwoNodeClusterTest extends AbstractClusterTest { assertEquals(testRealmOnBackend1.getRealm(), testRealmOnBackend2.getRealm()); failback(); - pause(1000); // UPDATE on node2 String realmUpdated = realm + "_updated"; testRealmOnBackend2.setRealm(realmUpdated); backend2AdminClient().realms().realm(realm).update(testRealmOnBackend2); if (containerFailover) { - stopBackend2(); + killBackend2(); } // check if updated on node1 testRealmOnBackend1 = backend1AdminClient().realms().realm(realmUpdated).toRepresentation(); @@ -77,7 +66,7 @@ public class TwoNodeClusterTest extends AbstractClusterTest { // DELETE on node1 backend1AdminClient().realms().realm(realmUpdated).remove(); if (containerFailover) { - stopBackend1(); + killBackend1(); } // check if deleted on node2 boolean testRealmOnBackend2Exists = false; @@ -91,48 +80,30 @@ public class TwoNodeClusterTest extends AbstractClusterTest { assertFalse(testRealmOnBackend2Exists); } - protected void listRealms(int i) { - log.info(String.format("Node %s: AccessTokenString: %s", i + 1, backendAdminClients.get(i).tokenManager().getAccessTokenString())); - for (RealmRepresentation r : backendAdminClients.get(i).realms().findAll()) { - log.info(String.format("Node %s: Realm: %s, Id: %s", i + 1, r.getRealm(), r.getId())); - } - } + @Test + public void createRealmViaFrontend() { + String realm = TEST + "_fe"; - protected ContainerInfo backend1Info() { - return backendNode(0); - } + RealmRepresentation testRealm = new RealmRepresentation(); + testRealm.setRealm(realm); + testRealm.setEnabled(true); - protected ContainerInfo backend2Info() { - return backendNode(1); - } + // CREATE on frontend + adminClient.realms().create(testRealm); - protected Keycloak backend1AdminClient() { - return backendAdminClients.get(0); - } + // check if created on frontend + RealmRepresentation testRealmOnFrontend = adminClient.realms().realm(realm).toRepresentation(); + assertEquals(testRealmOnFrontend.getRealm(), testRealm.getRealm()); - protected Keycloak backend2AdminClient() { - return backendAdminClients.get(1); - } + // check if created on node1 + RealmRepresentation testRealmOnBackend1 = backend1AdminClient().realms().realm(realm).toRepresentation(); + assertEquals(testRealmOnBackend1.getId(), testRealmOnFrontend.getId()); + assertEquals(testRealmOnBackend1.getRealm(), testRealmOnFrontend.getRealm()); - protected void startBackend1() { - startBackendNode(0); + // check if created on node2 + RealmRepresentation testRealmOnBackend2 = backend2AdminClient().realms().realm(realm).toRepresentation(); + assertEquals(testRealmOnBackend2.getId(), testRealmOnFrontend.getId()); + assertEquals(testRealmOnBackend2.getRealm(), testRealmOnFrontend.getRealm()); } - - protected void startBackend2() { - startBackendNode(1); - } - - protected void failback() { - startBackend1(); - startBackend2(); - } - - protected void stopBackend1() { - killBackendNode(0); - } - - protected void stopBackend2() { - killBackendNode(1); - } - + } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/SessionFailoverClusterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/SessionFailoverClusterTest.java new file mode 100644 index 0000000000..591e2e829e --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/SessionFailoverClusterTest.java @@ -0,0 +1,95 @@ +package org.keycloak.testsuite.cluster; + +import java.util.List; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import org.junit.Ignore; +import org.junit.Test; +import org.keycloak.representations.idm.RealmRepresentation; +import static org.keycloak.testsuite.auth.page.AuthRealm.ADMIN; +import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlDoesntStartWith; +import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith; +import static org.keycloak.testsuite.util.WaitUtils.pause; +import org.openqa.selenium.Cookie; + +/** + * + * @author tkyjovsk + */ +public class SessionFailoverClusterTest extends AbstractTwoNodeClusterTest { + + public static final String KEYCLOAK_SESSION_COOKIE = "KEYCLOAK_SESSION"; + public static final String KEYCLOAK_IDENTITY_COOKIE = "KEYCLOAK_IDENTITY"; + + @Override + public void addTestRealms(List testRealms) { + } + + @Test + @Ignore("work in progress") // only works with owners="2" at the moment + public void sessionFailover() { + + // LOGOUT + accountPage.navigateTo(); + driver.navigate().refresh(); + pause(3000); + loginPage.form().login(ADMIN, ADMIN); + assertCurrentUrlStartsWith(accountPage); + + Cookie sessionCookie = driver.manage().getCookieNamed(KEYCLOAK_SESSION_COOKIE); + assertNotNull(sessionCookie); + + killBackend1(); + + // check if session survived backend failure + + driver.navigate().refresh(); + pause(3000); + + assertCurrentUrlStartsWith(accountPage); + Cookie sessionCookieAfterFailover = driver.manage().getCookieNamed(KEYCLOAK_SESSION_COOKIE); + assertNotNull(sessionCookieAfterFailover); + assertEquals(sessionCookieAfterFailover.getValue(), sessionCookie.getValue()); + + failback(); + + // check if session survived backend failback + driver.navigate().refresh(); + pause(3000); + assertCurrentUrlStartsWith(accountPage); + Cookie sessionCookieAfterFailback = driver.manage().getCookieNamed(KEYCLOAK_SESSION_COOKIE); + assertNotNull(sessionCookieAfterFailback); + assertEquals(sessionCookieAfterFailover.getValue(), sessionCookie.getValue()); + + // LOGOUT + accountPage.navigateTo(); + accountPage.signOut(); + + assertCurrentUrlDoesntStartWith(accountPage); + masterRealmPage.navigateTo(); + sessionCookie = driver.manage().getCookieNamed(KEYCLOAK_SESSION_COOKIE); + assertNull(sessionCookie); + + killBackend1(); + + // check if session survived backend failure + driver.navigate().refresh(); + pause(3000); + assertCurrentUrlDoesntStartWith(accountPage); + masterRealmPage.navigateTo(); + sessionCookieAfterFailover = driver.manage().getCookieNamed(KEYCLOAK_SESSION_COOKIE); + assertNull(sessionCookieAfterFailover); + + failback(); + + // check if session survived backend failback + driver.navigate().refresh(); + pause(3000); + assertCurrentUrlDoesntStartWith(accountPage); + masterRealmPage.navigateTo(); + sessionCookieAfterFailback = driver.manage().getCookieNamed(KEYCLOAK_SESSION_COOKIE); + assertNull(sessionCookieAfterFailback); + } + +}