From 78c62ac0fa0d3bcb6659e759d548851c6b14f279 Mon Sep 17 00:00:00 2001 From: pvannierop Date: Tue, 9 Jan 2024 15:22:02 +0100 Subject: [PATCH] Working version of refactored tests --- .../security/AbstractContainerTest.java | 144 ++++++++++++++++-- .../security/OAuth2AuthIntegrationTest.java | 140 ++--------------- .../security/SamlAuthIntegrationTest.java | 129 ++-------------- .../test/integration/security/util/Util.java | 109 +++++++++++++ 4 files changed, 265 insertions(+), 257 deletions(-) diff --git a/src/test/java/org/cbioportal/test/integration/security/AbstractContainerTest.java b/src/test/java/org/cbioportal/test/integration/security/AbstractContainerTest.java index 399147aa718..e85703a5a55 100644 --- a/src/test/java/org/cbioportal/test/integration/security/AbstractContainerTest.java +++ b/src/test/java/org/cbioportal/test/integration/security/AbstractContainerTest.java @@ -1,13 +1,47 @@ package org.cbioportal.test.integration.security; import dasniko.testcontainers.keycloak.KeycloakContainer; -import org.cbioportal.test.integration.*; +import org.cbioportal.test.integration.MysqlInitializer; +import org.cbioportal.test.integration.OAuth2KeycloakInitializer; +import org.cbioportal.test.integration.SamlKeycloakInitializer; +import org.openqa.selenium.chrome.ChromeOptions; +import org.springframework.boot.web.context.WebServerInitializedEvent; +import org.springframework.context.ApplicationContextInitializer; +import org.springframework.context.ApplicationListener; +import org.springframework.context.ConfigurableApplicationContext; +import org.testcontainers.Testcontainers; +import org.testcontainers.containers.BindMode; import org.testcontainers.containers.BrowserWebDriverContainer; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.MySQLContainer; +import org.testcontainers.shaded.com.google.common.collect.ImmutableList; +import org.testcontainers.utility.DockerImageName; + +import java.io.File; +import java.io.IOException; +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; + +import static org.cbioportal.test.integration.security.util.Util.isHostMappingPresent; +import static org.testcontainers.containers.BrowserWebDriverContainer.VncRecordingMode.RECORD_ALL; public class AbstractContainerTest { - + + public final static int CBIO_PORT = 8080; + public final static int SESSION_SERVICE_PORT = 5000; + public final static int MONGO_PORT = 27017; + public final static int KEYCLOAK_PORT = 8084; + public final static int MYSQL_PORT = 3306; + public final static int MOCKSERVER_PORT = 8085; + public final static String DOWNLOAD_FOLDER = "/tmp/browser_downloads"; + + private static final String SESSION_IMAGE_VERSION = "docker.io/cbioportal/session-service:0.6.1"; + private static final String MONGO_IMAGE_VERSION = "docker.io/mongo:3.7.9"; + private static final String KEYCLOAK_IMAGE_VERSION = "quay.io/keycloak/keycloak:23.0"; + private static final String MYSQL_IMAGE_VERSION = "mysql:5.7"; + private static final String MOCKSERVER_IMAGE_VERSION = "docker.io/mockserver/mockserver:5.15.0"; + static final GenericContainer sessionServiceContainer; static final GenericContainer mongoContainer; static final MySQLContainer mysqlContainer; @@ -16,18 +50,110 @@ public class AbstractContainerTest { static final BrowserWebDriverContainer chromedriverContainer; static { + + String hostToCheck = "host.testcontainers.internal"; + String ipAddressToCheck = "localhost"; + try { + if (!isHostMappingPresent(hostToCheck, ipAddressToCheck)) { + throw new IllegalStateException(hostToCheck + " is not mapped to " + ipAddressToCheck + " in /etc/hosts. Please add this mapping."); + } + } catch (IOException e) { + throw new RuntimeException("Unable to read /etc/hosts file.", e); + } - sessionServiceContainer = SharedSessionServiceContainer.getInstance(); - mongoContainer = SharedMongoContainer.getInstance(); - mysqlContainer = SharedMysqlContainer.getInstance(); - mockServerContainer = MockServerContainer.getInstance(); - keycloakContainer = SharedKeycloakContainer.getInstance(); - chromedriverContainer = SharedChromeContainer.getInstance(); - + sessionServiceContainer = new GenericContainer(DockerImageName.parse(SESSION_IMAGE_VERSION)) + .withAccessToHost(true) + .withEnv("SERVER_PORT", "5000") + .withEnv("JAVA_OPTS", "-Dspring.data.mongodb.uri=mongodb://host.testcontainers.internal:27017/session-service"); + sessionServiceContainer.setPortBindings(ImmutableList.of(String.format("%s:5000", SESSION_SERVICE_PORT))); + + mongoContainer = new GenericContainer(DockerImageName.parse(MONGO_IMAGE_VERSION)) + .withEnv("MONGO_INITDB_DATABASE", "session_service") + .withReuse(true); + mongoContainer.setPortBindings(ImmutableList.of(String.format("%s:27017", MONGO_PORT, MONGO_PORT))); + + keycloakContainer = new KeycloakContainer(KEYCLOAK_IMAGE_VERSION) + .withRealmImportFile("security/keycloak-configuration-generated.json") + .withAdminUsername("admin") + .withAdminPassword("admin") + .withEnv("KC_HOSTNAME", "host.testcontainers.internal") + .withEnv("KC_HOSTNAME_ADMIN", "localhost") + .withReuse(true); + keycloakContainer.setPortBindings(ImmutableList.of(String.format("%s:8080", KEYCLOAK_PORT))); + + mockServerContainer = new GenericContainer(MOCKSERVER_IMAGE_VERSION) + .withExposedPorts(1080); + mockServerContainer.setPortBindings(ImmutableList.of(String.format("%s:1080", MOCKSERVER_PORT))); + + mysqlContainer = (MySQLContainer) new MySQLContainer(MYSQL_IMAGE_VERSION) + .withClasspathResourceMapping("cgds.sql", "/docker-entrypoint-initdb.d/a_schema.sql", BindMode.READ_ONLY) + .withClasspathResourceMapping("seed_mini.sql", "/docker-entrypoint-initdb.d/b_seed.sql", BindMode.READ_ONLY) + .withStartupTimeout(Duration.ofMinutes(10)) + .withReuse(true); + mysqlContainer.setPortBindings(ImmutableList.of(String.format("%s:3306", MYSQL_PORT))); + + ChromeOptions options = new ChromeOptions(); + Map prefs = new HashMap<>(); + prefs.put("download.default_directory", DOWNLOAD_FOLDER); + prefs.put("profile.default_content_settings.popups", 0); + prefs.put("download.prompt_for_download", "false"); + prefs.put("download.directory_upgrade", "true"); + options.setExperimentalOption("prefs", prefs); + + chromedriverContainer = new BrowserWebDriverContainer<>() + // activate this to record movies of the tests (greate for debugging) + .withRecordingMode(RECORD_ALL, new File("/home/pnp300")) + .withAccessToHost(true) + .withCapabilities(options) + .withReuse(true); + sessionServiceContainer.start(); mongoContainer.start(); mysqlContainer.start(); mockServerContainer.start(); keycloakContainer.start(); + chromedriverContainer.start(); + } + + // Update application properties with connection info on Keycloak container + public static class MySamlKeycloakInitializer extends SamlKeycloakInitializer { + @Override + public void initialize( + ConfigurableApplicationContext configurableApplicationContext) { + super.initializeImpl(configurableApplicationContext, keycloakContainer); + } + } + + // Update application properties with connection info on Keycloak container + public static class MyOAuth2KeycloakInitializer extends OAuth2KeycloakInitializer { + @Override + public void initialize( + ConfigurableApplicationContext configurableApplicationContext) { + super.initializeImpl(configurableApplicationContext, keycloakContainer); + } + } + + // Update application properties with connection info on Mysql container + public static class MyMysqlInitializer extends MysqlInitializer { + @Override + public void initialize( + ConfigurableApplicationContext configurableApplicationContext) { + super.initializeImpl(configurableApplicationContext, mysqlContainer); + } } + + // Expose the ports for the cBioPortal Spring application and keycloak inside + // the Chrome container. Each address is available on http://host.testcontainers.internal: + // in the browser container. + public static class PortInitializer implements + ApplicationContextInitializer { + @Override + public void initialize(ConfigurableApplicationContext applicationContext) { + applicationContext.addApplicationListener( + (ApplicationListener) event -> { + Testcontainers.exposeHostPorts(CBIO_PORT, KEYCLOAK_PORT, SESSION_SERVICE_PORT); + }); + } + } + } diff --git a/src/test/java/org/cbioportal/test/integration/security/OAuth2AuthIntegrationTest.java b/src/test/java/org/cbioportal/test/integration/security/OAuth2AuthIntegrationTest.java index 2076a35b382..f46d6859f6f 100644 --- a/src/test/java/org/cbioportal/test/integration/security/OAuth2AuthIntegrationTest.java +++ b/src/test/java/org/cbioportal/test/integration/security/OAuth2AuthIntegrationTest.java @@ -1,18 +1,13 @@ package org.cbioportal.test.integration.security; import org.cbioportal.PortalApplication; -import org.cbioportal.test.integration.*; +import org.cbioportal.test.integration.MysqlInitializer; +import org.cbioportal.test.integration.OAuth2KeycloakInitializer; +import org.cbioportal.test.integration.security.util.Util; import org.junit.FixMethodOrder; import org.junit.Test; -import org.junit.jupiter.api.Assertions; import org.junit.runner.RunWith; import org.junit.runners.MethodSorters; -import org.openqa.selenium.By; -import org.openqa.selenium.NoSuchElementException; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.remote.RemoteWebDriver; -import org.openqa.selenium.support.ui.ExpectedConditions; -import org.openqa.selenium.support.ui.WebDriverWait; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.web.context.WebServerInitializedEvent; import org.springframework.context.ApplicationContextInitializer; @@ -22,20 +17,9 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.util.Assert; import org.testcontainers.Testcontainers; -import org.testcontainers.containers.Container; -import org.testcontainers.containers.GenericContainer; -import javax.annotation.Nonnull; -import java.io.IOException; -import java.time.Duration; -import java.util.concurrent.Callable; -import java.util.concurrent.TimeUnit; - -import static org.cbioportal.test.integration.security.OAuth2AuthIntegrationTest.*; -import static org.cbioportal.test.integration.security.util.Util.isHostMappingPresent; -import static org.testcontainers.shaded.org.awaitility.Awaitility.await; +import static org.cbioportal.test.integration.security.OAuth2AuthIntegrationTest.MyKeycloakInitializer; @RunWith(SpringRunner.class) @SpringBootTest( @@ -72,9 +56,9 @@ } ) @ContextConfiguration(initializers = { - MyMysqlInitializer.class, + OAuth2AuthIntegrationTest.MyMysqlInitializer.class, MyKeycloakInitializer.class, - PortInitializer.class + OAuth2AuthIntegrationTest.PortInitializer.class }) @FixMethodOrder(MethodSorters.NAME_ASCENDING) @DirtiesContext // needed to reuse port 8080 for multiple tests @@ -86,21 +70,6 @@ public class OAuth2AuthIntegrationTest extends AbstractContainerTest { public final static String CBIO_URL_FROM_BROWSER = String.format("http://host.testcontainers.internal:%d", CBIO_PORT); -// @ClassRule -// public static SharedMysqlContainer mysqlContainer = SharedMysqlContainer.getInstance(); -// -// @ClassRule -// public static KeycloakContainer keycloakContainer = SharedKeycloakContainer.getInstance(); -// -// @ClassRule -// public static BrowserWebDriverContainer chrome = SharedChromeContainer.getInstance(); -// -// @ClassRule -// public static GenericContainer mongoContainer = SharedMongoContainer.getInstance(); -// -// @ClassRule -// public static GenericContainer sessionService = SharedSessionServiceContainer.getInstance(); - // Update application properties with connection info on Keycloak container public static class MyKeycloakInitializer extends OAuth2KeycloakInitializer { @Override @@ -133,111 +102,24 @@ public void initialize(ConfigurableApplicationContext applicationContext) { } } - // For these tests to work, the host name 'host.testcontainers.internal' - // must be mapped to 'localhost' in /etc/hosts/ file. - static { - String hostToCheck = "host.testcontainers.internal"; - String ipAddressToCheck = "localhost"; - try { - if (!isHostMappingPresent(hostToCheck, ipAddressToCheck)) { - throw new IllegalStateException(hostToCheck + " is not mapped to " + ipAddressToCheck + " in /etc/hosts. Please add this mapping."); - } - } catch (IOException e) { - throw new RuntimeException("Unable to read /etc/hosts file.", e); - } - } - @Test public void a_loginSuccess() { -// String vncAddress = chrome.getVncAddress(); - RemoteWebDriver driver = performLogin(); - WebElement loggedInButton = driver.findElement(By.id("dat-dropdown")); - Assertions.assertEquals("Logged in as testuser@thehyve.nl", loggedInButton.getText()); - Assertions.assertDoesNotThrow( - () -> driver.findElement(By.xpath("//span[.='Breast Invasive Carcinoma (TCGA,Nature 2012)']")), - "Study could not be found on the landing page. Permissions are not correctly passed from IDP to client."); + Util.testLogin(CBIO_URL_FROM_BROWSER, chromedriverContainer); } - + @Test public void b_downloadOfflineToken() throws Exception { - RemoteWebDriver driver = performLogin(); - Assertions.assertDoesNotThrow( - () -> driver.findElement(By.id("dat-dropdown")).click(), - "Logged-in menu could not be found on the page."); - driver.findElement(By.linkText("Data Access Token")).click(); - driver.findElement(By.xpath("//button[text()='Download Token']")).click(); - - await().atMost(Duration.ofSeconds(5)).until(downloadedFile()); - - Assertions.assertTrue(downloadedFile().call()); + Util.testDownloadOfflineToken(CBIO_URL_FROM_BROWSER, chromedriverContainer); } @Test public void c_logoutSuccess() { - RemoteWebDriver driver = performLogin(); - Assertions.assertDoesNotThrow( - () -> driver.findElement(By.id("dat-dropdown")).click(), - "Logout menu could not be found on the page."); - driver.findElement(By.linkText("Sign out")).click(); - Assertions.assertDoesNotThrow( - () -> driver.findElement(By.id("username")), - "IDP login screen not visible on the page. Logout did not work correctly." - ); + Util.testLogout(CBIO_URL_FROM_BROWSER, chromedriverContainer); } @Test public void d_loginAgainSuccess() { - final RemoteWebDriver driver = performLogin(); - Assertions.assertDoesNotThrow( - () -> driver.findElement(By.id("dat-dropdown")).click(), - "Logout menu could not be found on the page."); - driver.findElement(By.linkText("Sign out")).click(); - driver.manage().timeouts().pageLoadTimeout(10, TimeUnit.SECONDS); - Assertions.assertDoesNotThrow( - () -> driver.findElement(By.id("username")), - "IDP login screen not visible on the page. Logout did not work correctly." - ); - final RemoteWebDriver newDriver = performLogin(); - Assertions.assertDoesNotThrow( - () -> newDriver.findElement(By.id("dat-dropdown")), - "Logged-in menu could not be found on the page. Login did not work correctly."); - } - - private RemoteWebDriver performLogin() { - RemoteWebDriver driver = chromedriverContainer.getWebDriver(); - driver.get(CBIO_URL_FROM_BROWSER); - try { - // when the cbioportal logo is visible, skip login - driver.findElement(By.id("cbioportal-logo")); - } catch (NoSuchElementException e) { - WebElement userNameInput = driver.findElement(By.id("username")); - WebElement passwordInput = driver.findElement(By.id("password")); - WebElement loginButton = driver.findElement(By.id("kc-login")); - userNameInput.sendKeys("testuser"); - passwordInput.sendKeys("P@ssword1"); - loginButton.click(); - } - // wait for the page to load - new WebDriverWait(driver, Duration.ofSeconds(20)).until( - ExpectedConditions.presenceOfElementLocated(By.xpath("//*[@data-test='cancerTypeListContainer']"))); - return driver; - } - - private boolean containerFileExists( - @Nonnull final GenericContainer container, @Nonnull String path) - throws IOException, InterruptedException { - Assert.notNull(container, "Containers is null"); - Assert.isTrue(!path.isEmpty(), "Path string is empty"); - Container.ExecResult r = container.execInContainer("/bin/sh", "-c", - "if [ -f " + path - + " ] ; then echo '0' ; else (>&2 echo '1') ; fi"); - return !r.getStderr().contains("1"); - } - - private Callable downloadedFile() { - return () -> containerFileExists(chromedriverContainer, - String.format("%s/cbioportal_data_access_token.txt", - SharedChromeContainer.DOWNLOAD_FOLDER)); + Util.testLoginAgain(CBIO_URL_FROM_BROWSER, chromedriverContainer); } } \ No newline at end of file diff --git a/src/test/java/org/cbioportal/test/integration/security/SamlAuthIntegrationTest.java b/src/test/java/org/cbioportal/test/integration/security/SamlAuthIntegrationTest.java index 88aabb5cacc..f4a3265c1e7 100644 --- a/src/test/java/org/cbioportal/test/integration/security/SamlAuthIntegrationTest.java +++ b/src/test/java/org/cbioportal/test/integration/security/SamlAuthIntegrationTest.java @@ -1,20 +1,13 @@ package org.cbioportal.test.integration.security; -import dasniko.testcontainers.keycloak.KeycloakContainer; import org.cbioportal.PortalApplication; -import org.cbioportal.test.integration.*; -import org.junit.ClassRule; +import org.cbioportal.test.integration.MysqlInitializer; +import org.cbioportal.test.integration.SamlKeycloakInitializer; +import org.cbioportal.test.integration.security.util.Util; import org.junit.FixMethodOrder; import org.junit.Test; -import org.junit.jupiter.api.Assertions; import org.junit.runner.RunWith; import org.junit.runners.MethodSorters; -import org.openqa.selenium.By; -import org.openqa.selenium.NoSuchElementException; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.remote.RemoteWebDriver; -import org.openqa.selenium.support.ui.ExpectedConditions; -import org.openqa.selenium.support.ui.WebDriverWait; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.web.context.WebServerInitializedEvent; import org.springframework.context.ApplicationContextInitializer; @@ -24,20 +17,7 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.util.Assert; import org.testcontainers.Testcontainers; -import org.testcontainers.containers.BrowserWebDriverContainer; -import org.testcontainers.containers.Container; -import org.testcontainers.containers.GenericContainer; - -import javax.annotation.Nonnull; -import java.io.IOException; -import java.time.Duration; -import java.util.concurrent.Callable; -import java.util.concurrent.TimeUnit; - -import static org.cbioportal.test.integration.security.SamlAuthIntegrationTest.*; -import static org.testcontainers.shaded.org.awaitility.Awaitility.await; @RunWith(SpringRunner.class) @SpringBootTest( @@ -70,9 +50,9 @@ } ) @ContextConfiguration(initializers = { - MyMysqlInitializer.class, - MySamlKeycloakInitializer.class, - PortInitializer.class + SamlAuthIntegrationTest.MyMysqlInitializer.class, + SamlAuthIntegrationTest.MySamlKeycloakInitializer.class, + SamlAuthIntegrationTest.PortInitializer.class }) @FixMethodOrder(MethodSorters.NAME_ASCENDING) @DirtiesContext // needed to reuse port 8080 for multiple tests @@ -83,21 +63,6 @@ public class SamlAuthIntegrationTest extends AbstractContainerTest { private final static int SESSION_PORT = 27017; public final static String CBIO_URL_FROM_BROWSER = String.format("http://host.testcontainers.internal:%d", CBIO_PORT); - -// @ClassRule -// public static SharedMysqlContainer mysqlContainer = SharedMysqlContainer.getInstance(); -// -// @ClassRule -// public static KeycloakContainer keycloakContainer = SharedKeycloakContainer.getInstance(); -// -// @ClassRule -// public static BrowserWebDriverContainer chrome = SharedChromeContainer.getInstance(); -// -// @ClassRule -// public static GenericContainer mongoContainer = SharedMongoContainer.getInstance(); -// -// @ClassRule -// public static GenericContainer sessionService = SharedSessionServiceContainer.getInstance(); // Update application properties with connection info on Keycloak container public static class MySamlKeycloakInitializer extends SamlKeycloakInitializer { @@ -133,96 +98,22 @@ public void initialize(ConfigurableApplicationContext applicationContext) { @Test public void a_loginSuccess() { -// String vncAddress = chromedriverContainer.getVncAddress(); - RemoteWebDriver driver = performLogin(); - WebElement loggedInButton = driver.findElement(By.id("dat-dropdown")); - Assertions.assertEquals("Logged in as testuser@thehyve.nl", loggedInButton.getText()); - Assertions.assertDoesNotThrow( - () -> driver.findElement(By.xpath("//span[.='Breast Invasive Carcinoma (TCGA,Nature 2012)']")), - "Study could not be found on the landing page. Permissions are not correctly passed from IDP to client."); + Util.testLogin(CBIO_URL_FROM_BROWSER, chromedriverContainer); } @Test public void b_downloadOfflineToken() throws Exception { - RemoteWebDriver driver = performLogin(); - Assertions.assertDoesNotThrow( - () -> driver.findElement(By.id("dat-dropdown")).click(), - "Logged-in menu could not be found on the page."); - driver.findElement(By.linkText("Data Access Token")).click(); - driver.findElement(By.xpath("//button[text()='Download Token']")).click(); - - await().atMost(Duration.ofSeconds(5)).until(downloadedFile()); - - Assertions.assertTrue(downloadedFile().call()); + Util.testDownloadOfflineToken(CBIO_URL_FROM_BROWSER, chromedriverContainer); } @Test public void c_logoutSuccess() { - RemoteWebDriver driver = performLogin(); - Assertions.assertDoesNotThrow( - () -> driver.findElement(By.id("dat-dropdown")).click(), - "Logout menu could not be found on the page."); - driver.findElement(By.linkText("Sign out")).click(); - Assertions.assertDoesNotThrow( - () -> driver.findElement(By.id("username")), - "IDP login screen not visible on the page. Logout did not work correctly." - ); + Util.testLogout(CBIO_URL_FROM_BROWSER, chromedriverContainer); } @Test public void d_loginAgainSuccess() { - final RemoteWebDriver driver = performLogin(); - Assertions.assertDoesNotThrow( - () -> driver.findElement(By.id("dat-dropdown")).click(), - "Logout menu could not be found on the page."); - driver.findElement(By.linkText("Sign out")).click(); - driver.manage().timeouts().pageLoadTimeout(10, TimeUnit.SECONDS); - Assertions.assertDoesNotThrow( - () -> driver.findElement(By.id("username")), - "IDP login screen not visible on the page. Logout did not work correctly." - ); - final RemoteWebDriver newDriver = performLogin(); - Assertions.assertDoesNotThrow( - () -> newDriver.findElement(By.id("dat-dropdown")), - "Logged-in menu could not be found on the page. Login did not work correctly."); - } - - - private RemoteWebDriver performLogin() { - RemoteWebDriver driver = chromedriverContainer.getWebDriver(); - driver.get(CBIO_URL_FROM_BROWSER); - try { - // when the cbioportal logo is visible, skip login - driver.findElement(By.id("cbioportal-logo")); - } catch (NoSuchElementException e) { - WebElement userNameInput = driver.findElement(By.id("username")); - WebElement passwordInput = driver.findElement(By.id("password")); - WebElement loginButton = driver.findElement(By.id("kc-login")); - userNameInput.sendKeys("testuser"); - passwordInput.sendKeys("P@ssword1"); - loginButton.click(); - } - // wait for the page to load - new WebDriverWait(driver, Duration.ofSeconds(20)).until( - ExpectedConditions.presenceOfElementLocated(By.xpath("//*[@data-test='cancerTypeListContainer']"))); - return driver; - } - - private boolean containerFileExists( - @Nonnull final GenericContainer container, @Nonnull String path) - throws IOException, InterruptedException { - Assert.notNull(container, "Containers is null"); - Assert.isTrue(!path.isEmpty(), "Path string is empty"); - Container.ExecResult r = container.execInContainer("/bin/sh", "-c", - "if [ -f " + path - + " ] ; then echo '0' ; else (>&2 echo '1') ; fi"); - return !r.getStderr().contains("1"); - } - - private Callable downloadedFile() { - return () -> containerFileExists(chromedriverContainer, - String.format("%s/cbioportal_data_access_token.txt", - SharedChromeContainer.DOWNLOAD_FOLDER)); + Util.testLoginAgain(CBIO_URL_FROM_BROWSER, chromedriverContainer); } } \ No newline at end of file diff --git a/src/test/java/org/cbioportal/test/integration/security/util/Util.java b/src/test/java/org/cbioportal/test/integration/security/util/Util.java index ae210d8d21d..d505e46783b 100644 --- a/src/test/java/org/cbioportal/test/integration/security/util/Util.java +++ b/src/test/java/org/cbioportal/test/integration/security/util/Util.java @@ -1,8 +1,27 @@ package org.cbioportal.test.integration.security.util; +import org.cbioportal.test.integration.security.AbstractContainerTest; +import org.junit.jupiter.api.Assertions; +import org.openqa.selenium.By; +import org.openqa.selenium.NoSuchElementException; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.remote.RemoteWebDriver; +import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.WebDriverWait; +import org.springframework.util.Assert; +import org.testcontainers.containers.BrowserWebDriverContainer; +import org.testcontainers.containers.Container; +import org.testcontainers.containers.GenericContainer; + +import javax.annotation.Nonnull; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; +import java.time.Duration; +import java.util.concurrent.Callable; +import java.util.concurrent.TimeUnit; + +import static org.testcontainers.shaded.org.awaitility.Awaitility.await; public class Util { @@ -23,5 +42,95 @@ public static boolean isHostMappingPresent(String host, String ipAddress) throws return false; } + + public static void testLogin(String cbioUrl, BrowserWebDriverContainer chromedriverContainer) { + RemoteWebDriver driver = chromedriverContainer.getWebDriver(); + performLogin(cbioUrl, driver); + WebElement loggedInButton = driver.findElement(By.id("dat-dropdown")); + Assertions.assertEquals("Logged in as testuser@thehyve.nl", loggedInButton.getText()); + Assertions.assertDoesNotThrow( + () -> driver.findElement(By.xpath("//span[.='Breast Invasive Carcinoma (TCGA,Nature 2012)']")), + "Study could not be found on the landing page. Permissions are not correctly passed from IDP to client."); + } + + public static void testDownloadOfflineToken(String cbioUrl, BrowserWebDriverContainer chromedriverContainer) throws Exception { + RemoteWebDriver driver = chromedriverContainer.getWebDriver(); + performLogin(cbioUrl, driver); + Assertions.assertDoesNotThrow( + () -> driver.findElement(By.id("dat-dropdown")).click(), + "Logged-in menu could not be found on the page."); + driver.findElement(By.linkText("Data Access Token")).click(); + driver.findElement(By.xpath("//button[text()='Download Token']")).click(); + + await().atMost(Duration.ofSeconds(5)).until(downloadedFile(chromedriverContainer)); + + Assertions.assertTrue(downloadedFile(chromedriverContainer ).call()); + } + + public static void testLogout(String cbioUrl, BrowserWebDriverContainer chromedriverContainer) { + RemoteWebDriver driver = chromedriverContainer.getWebDriver(); + performLogin(cbioUrl, driver); + Assertions.assertDoesNotThrow( + () -> driver.findElement(By.id("dat-dropdown")).click(), + "Logout menu could not be found on the page."); + driver.findElement(By.linkText("Sign out")).click(); + Assertions.assertDoesNotThrow( + () -> driver.findElement(By.id("username")), + "IDP login screen not visible on the page. Logout did not work correctly." + ); + } + public static void testLoginAgain(String cbioUrl, BrowserWebDriverContainer chromedriverContainer) { + RemoteWebDriver driver = chromedriverContainer.getWebDriver(); + performLogin(cbioUrl, driver); + Assertions.assertDoesNotThrow( + () -> driver.findElement(By.id("dat-dropdown")).click(), + "Logout menu could not be found on the page."); + driver.findElement(By.linkText("Sign out")).click(); + driver.manage().timeouts().pageLoadTimeout(10, TimeUnit.SECONDS); + Assertions.assertDoesNotThrow( + () -> driver.findElement(By.id("username")), + "IDP login screen not visible on the page. Logout did not work correctly." + ); + performLogin(cbioUrl, driver); + Assertions.assertDoesNotThrow( + () -> driver.findElement(By.id("dat-dropdown")), + "Logged-in menu could not be found on the page. Login did not work correctly."); + } + + private static void performLogin(String url, RemoteWebDriver driver) { + driver.get(url); + try { + // when the cbioportal logo is visible, skip login + driver.findElement(By.id("cbioportal-logo")); + } catch (NoSuchElementException e) { + WebElement userNameInput = driver.findElement(By.id("username")); + WebElement passwordInput = driver.findElement(By.id("password")); + WebElement loginButton = driver.findElement(By.id("kc-login")); + userNameInput.sendKeys("testuser"); + passwordInput.sendKeys("P@ssword1"); + loginButton.click(); + } + // wait for the page to load + new WebDriverWait(driver, Duration.ofSeconds(20)).until( + ExpectedConditions.presenceOfElementLocated(By.xpath("//*[@data-test='cancerTypeListContainer']"))); + } + + private static boolean containerFileExists( + @Nonnull final GenericContainer container, @Nonnull String path) + throws IOException, InterruptedException { + Assert.notNull(container, "Containers is null"); + Assert.isTrue(!path.isEmpty(), "Path string is empty"); + Container.ExecResult r = container.execInContainer("/bin/sh", "-c", + "if [ -f " + path + + " ] ; then echo '0' ; else (>&2 echo '1') ; fi"); + return !r.getStderr().contains("1"); + } + + private static Callable downloadedFile(GenericContainer chromedriverContainer) { + return () -> containerFileExists(chromedriverContainer, + String.format("%s/cbioportal_data_access_token.txt", + AbstractContainerTest.DOWNLOAD_FOLDER)); + } + }