From 4d41008bd1b0d42f5f2dbf6c48e54722e4d7a296 Mon Sep 17 00:00:00 2001 From: Ursa Stutsman Date: Thu, 25 Jan 2018 15:04:55 -0500 Subject: [PATCH] Moving automation into workbench libs (#134) * use workbench libs * auth token for leo, other deletions, tweaks * adding methods to configs * adding some more info * forgot to render users.json * build/push swat tests docker image in jenkins build script * all up to date * syncing users json * Add campaignManagers to users * workbench-libs needs these (TODO remove) * fix for app conf * real fix for app conf * Hermione and Ron * more app conf fix * more app conf ctmpl * Update scalatest version for workbench-libs compatibility * implicits are the devil * dammit weasley * MORE PATIENCE * fix build script when pushing to develop * save git SHA during build script --- automation/docker/application.conf.ctmpl | 20 ++ automation/docker/run-tests.sh | 1 + automation/docker/users.json.ctmpl | 90 ++++++ automation/project/Dependencies.scala | 5 +- .../dsde/firecloud/api/Orchestration.scala | 258 ------------------ .../dsde/firecloud/api/Rawls.scala | 24 -- .../dsde/firecloud/api/Sam.scala | 54 ---- .../dsde/firecloud/api/Thurloe.scala | 75 ----- .../firecloud/config/FireCloudConfig.scala | 16 -- .../dsde/firecloud/page/FireCloudView.scala | 2 +- .../page/billing/BillingManagementPage.scala | 4 +- .../page/library/DataLibraryPage.scala | 2 +- .../page/methodrepo/MethodDetailPage.scala | 2 +- .../page/methodrepo/MethodRepoPage.scala | 2 +- .../dsde/firecloud/page/user/SignInPage.scala | 2 +- .../page/workspaces/WorkspaceDataPage.scala | 2 +- .../page/workspaces/WorkspaceListPage.scala | 2 +- .../workspaces/WorkspaceSummaryPage.scala | 6 +- .../WorkspaceMethodConfigDetailsPage.scala | 2 +- .../WorkspaceMethodConfigListPage.scala | 2 +- .../monitor/SubmissionDetailsPage.scala | 2 +- .../monitor/WorkspaceMonitorPage.scala | 2 +- .../dsde/firecloud/util/Retry.scala | 37 --- .../dsde/firecloud/util/Util.scala | 26 -- .../dsde/workbench/WebBrowserSpec.scala | 139 ---------- .../dsde/workbench/api/APIException.scala | 3 - .../dsde/workbench/api/WorkbenchClient.scala | 118 -------- .../dsde/workbench/config/AuthTokens.scala | 57 ---- .../dsde/workbench/config/Credentials.scala | 4 - .../dsde/workbench/config/LeoAuthToken.scala | 53 ++++ .../workbench/config/WorkbenchConfig.scala | 61 ----- .../dsde/workbench/dao/Google.scala | 16 -- .../leonardo/ClusterMonitoringSpec.scala | 5 +- .../workbench/leonardo/DummyClientPage.scala | 4 +- .../dsde/workbench/leonardo/Leonardo.scala | 11 +- .../workbench/leonardo/LeonardoConfig.scala | 6 +- .../leonardo/LeonardoTestUtils.scala | 34 ++- .../leonardo/NotebookInteractionSpec.scala | 11 +- .../workbench/leonardo/NotebookPage.scala | 2 +- .../leonardo/NotebooksListPage.scala | 2 +- .../workbench/page/CookieAuthedPage.scala | 4 +- .../workbench/util/ExceptionHandling.scala | 36 --- .../dsde/workbench/util/LocalFileUtil.scala | 1 + .../dsde/workbench/util/WebBrowserUtil.scala | 257 ----------------- docker/build.sh | 35 ++- 45 files changed, 252 insertions(+), 1245 deletions(-) create mode 100644 automation/docker/users.json.ctmpl delete mode 100644 automation/src/test/scala/org/broadinstitute/dsde/firecloud/api/Orchestration.scala delete mode 100644 automation/src/test/scala/org/broadinstitute/dsde/firecloud/api/Rawls.scala delete mode 100644 automation/src/test/scala/org/broadinstitute/dsde/firecloud/api/Sam.scala delete mode 100644 automation/src/test/scala/org/broadinstitute/dsde/firecloud/api/Thurloe.scala delete mode 100644 automation/src/test/scala/org/broadinstitute/dsde/firecloud/config/FireCloudConfig.scala delete mode 100644 automation/src/test/scala/org/broadinstitute/dsde/firecloud/util/Retry.scala delete mode 100644 automation/src/test/scala/org/broadinstitute/dsde/firecloud/util/Util.scala delete mode 100644 automation/src/test/scala/org/broadinstitute/dsde/workbench/WebBrowserSpec.scala delete mode 100644 automation/src/test/scala/org/broadinstitute/dsde/workbench/api/APIException.scala delete mode 100644 automation/src/test/scala/org/broadinstitute/dsde/workbench/api/WorkbenchClient.scala delete mode 100644 automation/src/test/scala/org/broadinstitute/dsde/workbench/config/AuthTokens.scala delete mode 100644 automation/src/test/scala/org/broadinstitute/dsde/workbench/config/Credentials.scala create mode 100644 automation/src/test/scala/org/broadinstitute/dsde/workbench/config/LeoAuthToken.scala delete mode 100644 automation/src/test/scala/org/broadinstitute/dsde/workbench/config/WorkbenchConfig.scala delete mode 100644 automation/src/test/scala/org/broadinstitute/dsde/workbench/dao/Google.scala delete mode 100644 automation/src/test/scala/org/broadinstitute/dsde/workbench/util/ExceptionHandling.scala delete mode 100644 automation/src/test/scala/org/broadinstitute/dsde/workbench/util/WebBrowserUtil.scala diff --git a/automation/docker/application.conf.ctmpl b/automation/docker/application.conf.ctmpl index 4e2e663511c..c13b669a1d4 100644 --- a/automation/docker/application.conf.ctmpl +++ b/automation/docker/application.conf.ctmpl @@ -3,6 +3,7 @@ {{with $environment := env "ENVIRONMENT"}} {{with $dir := env "ROOT_DIR"}} {{with $local_ui := env "LOCAL_UI"}} +{{with $trialBillingPemSecrets := vault (printf "secret/dsde/firecloud/%s/common/trial-billing-account.pem" $environment)}} {{with $users := vault (printf "secret/dsde/firecloud/%s/common/users" $environment)}} {{with $secrets := vault (printf "secret/dsde/firecloud/%s/common/secrets" $environment)}} {{with $leoServiceAccount := vault (printf "secret/dsde/firecloud/%s/leonardo/leonardo-swagger-account.json" $environment)}} @@ -43,11 +44,29 @@ gcs { qaPemFile = "{{$dir}}/src/test/resources/firecloud-account.pem" billingAccount = "Broad Institute - 8201528" billingAccountId = "billingAccounts/00708C-45D19D-27AAFA" + trialBillingPemFile = "{{$dir}}/src/test/resources/trial-billing-account.pem" + trialBillingPemFileClientId = "{{$trialBillingPemSecrets.Data.client_email}}" + smoketestsProject = {{if eq $environment "prod"}}"broad-dsde-{{$environment}}-smoketests"{{else}}"broad-dsde-{{$environment}}"{{end}} + appsDomain = {{if eq $environment "qa"}}"quality.firecloud.org"{{else}}"{{$environment}}.test.firecloud.org"{{end}} } +methods { + testMethod = "DO_NOT_CHANGE_test_method" + testMethodConfig = "DO_NOT_CHANGE_test1_config" + methodConfigNamespace = "automationmethods" + snapshotID = 1 +} + users { notSoSecretPassword = "{{$users.Data.automation_users_passwd}}" + userDataPath = "{{$dir}}/src/test/resources/users.json" + + # TODO: these settings only apply to UI but are required by workbench-libs + + tempSubjectId = "{{if or (eq $environment "dev") (eq $environment "alpha")}}111010567286567716739{{else if eq $environment "qa"}}117891551413045861932{{else}}[undefined]{{end}}" + smoketestpassword = "{{$users.Data.users_passwd}}" + smoketestuser = {{if eq $environment "prod"}}"b.adm.firec@gmail.com"{{else}}"hermione.owner@{{template "USER_DOMAIN"}}"{{end}} dumbledore = "dumbledore.admin@{{template "USER_DOMAIN"}}" voldemort = "voldemort.admin@{{template "USER_DOMAIN"}}" @@ -77,3 +96,4 @@ chromeSettings { {{end}} {{end}} {{end}} +{{end}} diff --git a/automation/docker/run-tests.sh b/automation/docker/run-tests.sh index 8144ab6001e..4d2b948e985 100755 --- a/automation/docker/run-tests.sh +++ b/automation/docker/run-tests.sh @@ -104,6 +104,7 @@ docker run -e DOCKERHOST=$DOCKERHOST \ -P --rm -t -e CHROME_URL="http://hub:4444/" ${HOST_MAPPING} \ -v $WORKING_DIR/target/application.conf:/app/src/test/resources/application.conf \ -v $WORKING_DIR/target/firecloud-account.pem:/app/src/test/resources/firecloud-account.pem \ + -v $WORKING_DIR/target/users.json:/app/src/test/resources/users.json \ -v $WORKING_DIR/target:/app/target \ -v $WORKING_DIR/chrome/downloads:/app/chrome/downloads \ -v $WORKING_DIR/failure_screenshots:/app/failure_screenshots \ diff --git a/automation/docker/users.json.ctmpl b/automation/docker/users.json.ctmpl new file mode 100644 index 00000000000..ee1c5a4e84e --- /dev/null +++ b/automation/docker/users.json.ctmpl @@ -0,0 +1,90 @@ +{{with $environment := env "ENVIRONMENT"}} +{{if eq $environment "qa"}} +{ + "admins": { + "dumbledore": "dumbledore.admin@quality.firecloud.org", + "voldemort": "voldemort.admin@quality.firecloud.org" + }, + "owners": { + "hermione": "hermione.owner@quality.firecloud.org", + "sirius": "sirius.owner@quality.firecloud.org", + "tonks": "tonks.owner@quality.firecloud.org" + }, + "curators": { + "mcgonagall": "mcgonagall.curator@quality.firecloud.org", + "snape": "snape.curator@quality.firecloud.org", + "hagrid": "hagrid.curator@quality.firecloud.org", + "lupin": "lupin.curator@quality.firecloud.org", + "flitwick": "flitwick.curator@quality.firecloud.org" + }, + "authdomains": { + "fred": "fred.authdomain@quality.firecloud.org", + "george": "george.authdomain@quality.firecloud.org", + "bill": "bill.authdomain@quality.firecloud.org", + "percy": "percy.authdomain@quality.firecloud.org", + "molly": "molly.authdomain@quality.firecloud.org", + "arthur": "arthur.authdomain@quality.firecloud.org" + }, + "students": { + "harry": "harry.potter@quality.firecloud.org", + "ron": "ron.weasley@quality.firecloud.org", + "lavender": "lavender.brown@quality.firecloud.org", + "cho": "cho.chang@quality.firecloud.org", + "oliver": "oliver.wood@quality.firecloud.org", + "cedric": "cedric.diggory@quality.firecloud.org", + "crabbe": "vincent.crabbe@quality.firecloud.org", + "goyle": "gregory.goyle@quality.firecloud.org", + "dean": "dean.thomas@quality.firecloud.org", + "ginny": "ginny.weasley@quality.firecloud.org" + }, + "temps": { + "luna": "luna.temp@quality.firecloud.org", + "neville": "neville.temp@quality.firecloud.org" + }, + "notebookswhitelisted": { + "hermione": "hermione.owner@quality.firecloud.org", + "ron": "ron.weasley@quality.firecloud.org" + }, + "campaignManagers": { + "dumbledore": "dumbledore.admin@test.firecloud.org", + "voldemort": "voldemort.admin@test.firecloud.org" + } +} +{{else}} +{ + "admins": { + "dumbledore": "dumbledore.admin@test.firecloud.org", + "voldemort": "voldemort.admin@test.firecloud.org" + }, + "owners": { + "hermione": "hermione.owner@test.firecloud.org" + }, + "curators": { + "mcgonagall": "mcgonagall.curator@test.firecloud.org", + "snape": "snape.curator@test.firecloud.org" + }, + "authdomains": { + "fred": "fred.authdomain@test.firecloud.org", + "george": "george.authdomain@test.firecloud.org", + "bill": "bill.authdomain@test.firecloud.org" + }, + "students": { + "harry": "harry.potter@test.firecloud.org", + "ron": "ron.weasley@test.firecloud.org", + "draco": "draco.malfoy@test.firecloud.org" + }, + "temps": { + "luna": "luna.temp@test.firecloud.org", + "neville": "neville.temp@test.firecloud.org" + }, + "notebookswhitelisted": { + "hermione": "hermione.owner@test.firecloud.org", + "ron": "ron.weasley@test.firecloud.org" + }, + "campaignManagers": { + "dumbledore": "dumbledore.admin@test.firecloud.org", + "voldemort": "voldemort.admin@test.firecloud.org" + } +} +{{end}} +{{end}} diff --git a/automation/project/Dependencies.scala b/automation/project/Dependencies.scala index 1cca216d151..b869934ee26 100644 --- a/automation/project/Dependencies.scala +++ b/automation/project/Dependencies.scala @@ -7,11 +7,13 @@ object Dependencies { val workbenchModelV = "0.8-d97f551" val workbenchGoogleV = "0.10-b95b2c1" + val serviceTestV = "0.1-c5a3162-SNAP" val excludeWorkbenchModel = ExclusionRule(organization = "org.broadinstitute.dsde.workbench", name = "workbench-model_2.11") val workbenchModel: ModuleID = "org.broadinstitute.dsde.workbench" %% "workbench-model" % workbenchModelV val workbenchGoogle: ModuleID = "org.broadinstitute.dsde.workbench" %% "workbench-google" % workbenchGoogleV excludeAll excludeWorkbenchModel + val workbenchServiceTest: ModuleID = "org.broadinstitute.dsde.workbench" %% "workbench-service-test" % serviceTestV % "test" classifier "tests" excludeAll excludeWorkbenchModel val rootDependencies = Seq( // proactively pull in latest versions of Jackson libs, instead of relying on the versions @@ -35,13 +37,14 @@ object Dependencies { "com.typesafe.akka" %% "akka-testkit" % akkaV % "test", "com.typesafe.akka" %% "akka-slf4j" % akkaV, "org.specs2" %% "specs2-core" % "3.7" % "test", - "org.scalatest" %% "scalatest" % "2.2.6" % "test", + "org.scalatest" %% "scalatest" % "3.0.1" % "test", "org.seleniumhq.selenium" % "selenium-java" % "3.8.1" % "test", "com.typesafe.scala-logging" %% "scala-logging" % "3.1.0", "org.apache.commons" % "commons-text" % "1.2", workbenchModel, workbenchGoogle, + workbenchServiceTest, // required by workbenchGoogle "com.typesafe.akka" %% "akka-http-spray-json" % "10.0.6" % "provided" diff --git a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/api/Orchestration.scala b/automation/src/test/scala/org/broadinstitute/dsde/firecloud/api/Orchestration.scala deleted file mode 100644 index cde47fa735f..00000000000 --- a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/api/Orchestration.scala +++ /dev/null @@ -1,258 +0,0 @@ -package org.broadinstitute.dsde.firecloud.api - -import com.typesafe.scalalogging.LazyLogging -import org.broadinstitute.dsde.firecloud.api.WorkspaceAccessLevel.WorkspaceAccessLevel -import org.broadinstitute.dsde.firecloud.config.FireCloudConfig -import org.broadinstitute.dsde.firecloud.util.Retry.retry -import org.broadinstitute.dsde.workbench.api.WorkbenchClient -import org.broadinstitute.dsde.workbench.config.AuthToken - -import scala.concurrent.duration._ - - -trait Orchestration extends WorkbenchClient with LazyLogging { - - def responseAsList(response: String): List[Map[String, Object]] = { - mapper.readValue(response, classOf[List[Map[String, Object]]]) - } - - private def apiUrl(s: String) = { - FireCloudConfig.FireCloud.orchApiUrl + s - } - - object billing { - - object BillingProjectRole extends Enumeration { - type BillingProjectRole = Value - val User = Value("user") - val Owner = Value("owner") - } - import BillingProjectRole._ - - def addUserToBillingProject(projectName: String, email: String, role: BillingProjectRole)(implicit token: AuthToken): Unit = { - logger.info(s"Adding user to billing project: $projectName $email ${role.toString}") - putRequest(apiUrl(s"api/billing/$projectName/${role.toString}/$email")) - } - - def removeUserFromBillingProject(projectName: String, email: String, role: BillingProjectRole)(implicit token: AuthToken): Unit = { - logger.info(s"Removing user from billing project: $projectName $email ${role.toString}") - deleteRequest(apiUrl(s"api/billing/$projectName/${role.toString}/$email")) - } - - def addGoogleRoleToBillingProjectUser(projectName: String, email: String, googleRole: String)(implicit token: AuthToken): Unit = { - logger.info(s"Adding google role $googleRole to user $email in billing project $projectName") - putRequest(apiUrl(s"api/billing/$projectName/googleRole/$googleRole/$email")) - } - - def removeGoogleRoleFromBillingProjectUser(projectName: String, email: String, googleRole: String)(implicit token: AuthToken): Unit = { - logger.info(s"Removing google role $googleRole from user $email in billing project $projectName") - deleteRequest(apiUrl(s"api/billing/$projectName/googleRole/$googleRole/$email")) - } - - def createBillingProject(projectName: String, billingAccount: String)(implicit token: AuthToken): Unit = { - logger.info(s"Creating billing project: $projectName $billingAccount") - postRequest(apiUrl("api/billing"), Map("projectName" -> projectName, "billingAccount" -> billingAccount)) - - retry(10.seconds, 10.minutes)({ - val response: String = parseResponse(getRequest(apiUrl("api/profile/billing"))) - val projects: List[Map[String, Object]] = responseAsList(response) - projects.find((e) => - e.exists(_ == ("creationStatus", "Ready")) && e.exists(_ == ("projectName", projectName))) - }) match { - case None => throw new Exception("Billing project creation did not complete") - case Some(_) => logger.info(s"Finished creating billing project: $projectName $billingAccount") - } - } - } - - object groups { - - object GroupRole extends Enumeration { - type GroupRole = Value - val Member = Value("member") - val Admin = Value("admin") - } - import GroupRole._ - - def addUserToGroup(groupName: String, email: String, role: GroupRole)(implicit token: AuthToken): Unit = { - logger.info(s"Adding user to group: $groupName $email ${role.toString}") - putRequest(apiUrl(s"api/groups/$groupName/${role.toString}/$email")) - } - - def create(groupName: String)(implicit token: AuthToken): Unit = { - logger.info(s"Creating group: $groupName") - postRequest(apiUrl(s"api/groups/$groupName")) - } - - def delete(groupName: String)(implicit token: AuthToken): Unit = { - logger.info(s"Deleting group: $groupName") - deleteRequest(apiUrl(s"api/groups/$groupName")) - } - - def removeUserFromGroup(groupName: String, email: String, role: GroupRole)(implicit token: AuthToken): Unit = { - logger.info(s"Removing user from group: $groupName $email ${role.toString}") - deleteRequest(apiUrl(s"api/groups/$groupName/${role.toString}/$email")) - } - } - - object workspaces { - - def create(namespace: String, name: String, authDomain: Set[String] = Set.empty) - (implicit token: AuthToken): Unit = { - logger.info(s"Creating workspace: $namespace/$name authDomain: $authDomain") - - val authDomainGroups = authDomain.map(a => Map("membersGroupName" -> a)) - - val request = Map("namespace" -> namespace, "name" -> name, - "attributes" -> Map.empty, "authorizationDomain" -> authDomainGroups) - - postRequest(apiUrl(s"api/workspaces"), request) - } - - def delete(namespace: String, name: String)(implicit token: AuthToken): Unit = { - logger.info(s"Deleting workspace: $namespace/$name") - deleteRequest(apiUrl(s"api/workspaces/$namespace/$name")) - } - - def updateAcl(namespace: String, name: String, email: String, accessLevel: WorkspaceAccessLevel)(implicit token: AuthToken): Unit = { - updateAcl(namespace, name, List(AclEntry(email, accessLevel))) - } - - def updateAcl(namespace: String, name: String, aclEntries: List[AclEntry] = List())(implicit token: AuthToken): Unit = { - logger.info(s"Updating ACLs for workspace: $namespace/$name $aclEntries") - patchRequest(apiUrl(s"api/workspaces/$namespace/$name/acl"), - aclEntries.map(e => Map("email" -> e.email, "accessLevel" -> e.accessLevel.toString))) - } - } - - - /* - * Library requests - */ - - object library { - def setLibraryAttributes(ns: String, name: String, attributes: Map[String, Any])(implicit token: AuthToken): String = { - logger.info(s"Setting library attributes for workspace: $ns/$name $attributes") - putRequest(apiUrl(s"api/library/$ns/$name/metadata"), attributes) - } - - def setDiscoverableGroups(ns: String, name: String, groupNames: List[String])(implicit token: AuthToken): String = { - logger.info(s"Setting discoverable groups for workspace: $ns/$name $groupNames") - putRequest(apiUrl(s"api/library/$ns/$name/discoverableGroups"), groupNames) - } - - def publishWorkspace(ns: String, name: String)(implicit token: AuthToken): String = { - logger.info(s"Publishing workspace: $ns/$name") - postRequest(apiUrl(s"api/library/$ns/$name/published")) - } - - def unpublishWorkspace(ns: String, name: String)(implicit token: AuthToken): String = { - logger.info(s"Unpublishing workspace: $ns/$name") - deleteRequest(apiUrl(s"api/library/$ns/$name/published")) - } - } - - /* - * Method Configurations requests - */ - - object methodConfigurations { - - // This only works for method configs, but not methods - def copyMethodConfigFromMethodRepo(ns: String, wsName: String, configurationNamespace: String, configurationName: String, configurationSnapshotId: Int, destinationNamespace: String, destinationName: String)(implicit token: AuthToken): String = { - logger.info(s"Copying method config from method repo: $ns/$wsName config: $configurationNamespace/$configurationName $configurationSnapshotId destination: $destinationNamespace/$destinationName") - postRequest(apiUrl(s"api/workspaces/$ns/$wsName/method_configs/copyFromMethodRepo"), - Map("configurationNamespace" -> configurationNamespace, "configurationName" -> configurationName, "configurationSnapshotId" -> configurationSnapshotId, "destinationNamespace" -> destinationNamespace, "destinationName" -> destinationName)) - } - - def createMethodConfigInWorkspace(ns: String, wsName: String, methodConfigVersion: Int, - methodNamespace: String, methodName: String, methodVersion: Int, - destinationNamespace: String, destinationName: String, inputs: Map[String, String], outputs: Map[String, String], - rootEntityType: String)(implicit token: AuthToken): String = { - logger.info(s"Creating method config: $ns/$wsName $methodConfigVersion method: $methodNamespace/$methodName destination: $destinationNamespace/$destinationName") - postRequest(apiUrl(s"api/workspaces/$ns/$wsName/methodconfigs"), - Map("deleted" -> false, - "inputs" -> inputs, - "methodConfigVersion" -> methodConfigVersion, - "methodRepoMethod" -> Map("methodNamespace" -> methodNamespace, "methodName" -> methodName, "methodVersion" -> methodVersion), - "namespace" -> destinationNamespace, - "name" -> destinationName, - "outputs" -> outputs, - "prerequisites" -> Map(), - "rootEntityType" -> rootEntityType) - ) - } - - def createMethodConfig(methodConfigData: Map[String,Any])(implicit token: AuthToken): String = { - logger.info(s"Adding a method config") - postRequest(apiUrl(s"api/configurations"), methodConfigData) - } - - def getMethodConfigPermission(configNamespace: String)(implicit token: AuthToken): String = { - logger.info(s"Getting permissions for method config: $configNamespace") - parseResponse(getRequest(apiUrl(s"api/configurations/$configNamespace/permissions"))) - } - def setMethodConfigPermission(configNamespace: String, configName: String, configSnapshotId: Int, user: String, role: String)(implicit token: AuthToken): String = { - logger.info(s"Setting permissions for method config: $configNamespace/$configName/$configSnapshotId and user: $user to role: $role") - postRequest(apiUrl(s"api/configurations/$configNamespace/$configName/$configSnapshotId/permissions"), - Seq(Map("user" -> user, - "role" -> role)) - ) - } - } - - object methods { - def createMethod(methodData: Map[String,Any])(implicit token: AuthToken): Unit = { - logger.info(s"Adding a method.") - postRequest(apiUrl(s"api/methods"), methodData) - } - - def redact(ns: String, name: String, snapshotId: Int)(implicit token: AuthToken): Unit = { - logger.info(s"Redacting method: $ns/$name:$snapshotId") - deleteRequest(apiUrl(s"api/methods/$ns/$name/$snapshotId")) - } - - def getMethodPermissions(ns: String, name: String, snapshotId: Int)(implicit token: AuthToken): String = { - logger.info(s"Getting method permissions for $ns / $name") - parseResponse(getRequest(apiUrl(s"api/methods/$ns/$name/$snapshotId/permissions"))) - } - } - - /* - * Submissions requests - */ - - object submissions { - def launchWorkflow(ns: String, wsName: String, methodConfigurationNamespace: String, methodConfigurationName: String, entityType: String, entityName: String, expression: String, useCallCache: Boolean, workflowFailureMode: String = "NoNewCalls")(implicit token: AuthToken): String = { - logger.info(s"Creating a submission: $ns/$wsName config: $methodConfigurationNamespace/$methodConfigurationName") - postRequest(apiUrl(s"api/workspaces/$ns/$wsName/submissions"), - Map("methodConfigurationNamespace" -> methodConfigurationNamespace, "methodConfigurationName" -> methodConfigurationName, "entityType" -> entityType, "entityName" -> entityName, "expression" -> expression, "useCallCache" -> useCallCache, "workflowFailureMode" -> workflowFailureMode)) - } - - } - - - /* - * Workspace requests - */ - - def importMetaData(ns: String, wsName: String, fileName: String, fileContent: String)(implicit token: AuthToken): String = { - logger.info(s"Importing metadata: $ns/$wsName $fileName") - postRequestWithMultipart(apiUrl(s"api/workspaces/$ns/$wsName/importEntities"), fileName, fileContent) - } - -} -object Orchestration extends Orchestration - -/** - * Dictionary of access level values expected by the web service API. - */ -object WorkspaceAccessLevel extends Enumeration { - type WorkspaceAccessLevel = Value - val NoAccess = Value("NO ACCESS") - val Owner = Value("OWNER") - val Reader = Value("READER") - val Writer = Value("WRITER") -} - -case class AclEntry(email: String, accessLevel: WorkspaceAccessLevel) diff --git a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/api/Rawls.scala b/automation/src/test/scala/org/broadinstitute/dsde/firecloud/api/Rawls.scala deleted file mode 100644 index f825ba2b0da..00000000000 --- a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/api/Rawls.scala +++ /dev/null @@ -1,24 +0,0 @@ -package org.broadinstitute.dsde.firecloud.api - -import akka.http.scaladsl.model.StatusCodes -import com.typesafe.scalalogging.LazyLogging -import org.broadinstitute.dsde.firecloud.config.FireCloudConfig -import org.broadinstitute.dsde.workbench.api.WorkbenchClient -import org.broadinstitute.dsde.workbench.config.AuthToken - -/** - * Rawls API service client. This should only be used when Orchestration does - * not provide a required endpoint. This should primarily be used for admin - * functions. - */ -object Rawls extends WorkbenchClient with LazyLogging { - - private val url = FireCloudConfig.FireCloud.rawlsApiUrl - - object admin { - def deleteBillingProject(projectName: String)(implicit token: AuthToken): Unit = { - logger.info(s"Deleting billing project: $projectName") - deleteRequest(url + s"api/admin/billing/$projectName") - } - } -} diff --git a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/api/Sam.scala b/automation/src/test/scala/org/broadinstitute/dsde/firecloud/api/Sam.scala deleted file mode 100644 index 57128068199..00000000000 --- a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/api/Sam.scala +++ /dev/null @@ -1,54 +0,0 @@ -package org.broadinstitute.dsde.firecloud.api - -import akka.http.scaladsl.model.StatusCodes -import com.typesafe.scalalogging.LazyLogging -import org.broadinstitute.dsde.firecloud.api.Sam.user.UserStatusDetails -import org.broadinstitute.dsde.firecloud.config.FireCloudConfig -import org.broadinstitute.dsde.workbench.api.WorkbenchClient -import org.broadinstitute.dsde.workbench.config.AuthToken -import org.broadinstitute.dsde.workbench.model.WorkbenchEmail -import org.broadinstitute.dsde.workbench.model.google.{GoogleProject, ServiceAccountName} - -/** - * Sam API service client. This should only be used when Orchestration does - * not provide a required endpoint. This should primarily be used for admin - * functions. - */ -object Sam extends WorkbenchClient with LazyLogging { - - private val url = FireCloudConfig.FireCloud.samApiUrl - - def petName(userInfo: UserStatusDetails) = ServiceAccountName(s"pet-${userInfo.userSubjectId}") - - object admin { - - def deleteUser(subjectId: String)(implicit token: AuthToken): Unit = { - logger.info(s"Deleting user: $subjectId") - deleteRequest(url + s"api/admin/user/$subjectId") - } - - def doesUserExist(subjectId: String)(implicit token: AuthToken): Option[Boolean] = { - getRequest(url + s"api/admin/user/$subjectId").status match { - case StatusCodes.OK => Option(true) - case StatusCodes.NotFound => Option(false) - case _ => None - } - } - } - - object user { - case class UserStatusDetails(userSubjectId: String, userEmail: String) - case class UserStatus(userInfo: UserStatusDetails, enabled: Map[String, Boolean]) - - def status()(implicit token: AuthToken): Option[UserStatus] = { - logger.info(s"Getting user registration status") - parseResponseOption[UserStatus](getRequest(url + "register/user")) - } - - def petServiceAccountEmail(googleProject: GoogleProject)(implicit token: AuthToken): WorkbenchEmail = { - logger.info(s"Getting pet service account email") - val petEmailStr = parseResponseAs[String](getRequest(s"$url/api/google/user/petServiceAccount/${googleProject.value}")) - WorkbenchEmail(petEmailStr) - } - } -} diff --git a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/api/Thurloe.scala b/automation/src/test/scala/org/broadinstitute/dsde/firecloud/api/Thurloe.scala deleted file mode 100644 index 8e845c35cb5..00000000000 --- a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/api/Thurloe.scala +++ /dev/null @@ -1,75 +0,0 @@ -package org.broadinstitute.dsde.firecloud.api - -import akka.http.scaladsl.model.headers.{ModeledCustomHeader, ModeledCustomHeaderCompanion} -import com.typesafe.scalalogging.LazyLogging -import org.broadinstitute.dsde.firecloud.config.FireCloudConfig -import org.broadinstitute.dsde.workbench.api.WorkbenchClient -import org.broadinstitute.dsde.workbench.config.AuthToken - -import scala.util.Try - -/** - */ -object Thurloe extends WorkbenchClient with LazyLogging { - - private val thurloeHeaders = List(FireCloudIdHeader(FireCloudConfig.FireCloud.fireCloudId)) - private val url = FireCloudConfig.FireCloud.thurloeApiUrl - - object FireCloudIdHeader extends ModeledCustomHeaderCompanion[FireCloudIdHeader] { - override def name: String = "X-FireCloud-Id" - override def parse(value: String): Try[FireCloudIdHeader] = Try(FireCloudIdHeader(value)) - } - case class FireCloudIdHeader(id: String) extends ModeledCustomHeader[FireCloudIdHeader] { - override def companion: ModeledCustomHeaderCompanion[FireCloudIdHeader] = FireCloudIdHeader - override def renderInRequests(): Boolean = true - override def renderInResponses(): Boolean = false - override def value(): String = id - } - - object keyValuePairs { - - def delete(subjectId: String, key: String)(implicit token: AuthToken): Unit = { - logger.info(s"Deleting $key for $subjectId") - deleteRequest(url + s"api/thurloe/$subjectId/$key", thurloeHeaders) - } - - def deleteAll(subjectId: String)(implicit token: AuthToken): Unit = { - logger.info(s"Deleting all key/value pairs from for $subjectId") - getAll(subjectId).foreach[Unit] { - case (key, _) => - delete(subjectId, key) - } - } - - def getAll(subjectId: String)(implicit token: AuthToken): Map[String, String] = { - - def extractTupleFromKeyValueMap(m: Map[String, String]): Option[(String, String)] = - (m.get("key"), m.get("value")) match { - case (Some(k), Some(v)) => Some(k -> v) - case _ => None - } - - val response: String = parseResponse(getRequest(url + s"api/thurloe/$subjectId", thurloeHeaders)) - - /* - * "keyValuePairs" contains a list of maps, each with 2 entries: one for - * the key and one for the value. To make it easier to work with, we need - * to turn this: - * - * List( - * Map("key" -> "foo1", "value" -> "bar1"), - * Map("key" -> "foo2", "value" -> "bar2")) - * - * into this: - * - * Map("foo1" -> "bar1", "foo2" -> "bar2") - * - */ - response.fromJsonMapAs[List[Map[String, String]]]("keyValuePairs") match { - case Some(maps) => maps.flatMap(m => extractTupleFromKeyValueMap(m)).toMap - case None => Map() - } - } - } -} - diff --git a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/config/FireCloudConfig.scala b/automation/src/test/scala/org/broadinstitute/dsde/firecloud/config/FireCloudConfig.scala deleted file mode 100644 index 4b89d7ae35b..00000000000 --- a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/config/FireCloudConfig.scala +++ /dev/null @@ -1,16 +0,0 @@ -package org.broadinstitute.dsde.firecloud.config - -import org.broadinstitute.dsde.workbench.config.WorkbenchConfig - -object FireCloudConfig extends WorkbenchConfig { - private val fireCloud = config.getConfig("fireCloud") - - object FireCloud { - val baseUrl: String = fireCloud.getString("baseUrl") - val fireCloudId: String = fireCloud.getString("fireCloudId") - val orchApiUrl: String = fireCloud.getString("orchApiUrl") - val rawlsApiUrl: String = fireCloud.getString("rawlsApiUrl") - val samApiUrl: String = fireCloud.getString("samApiUrl") - val thurloeApiUrl: String = fireCloud.getString("thurloeApiUrl") - } -} diff --git a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/FireCloudView.scala b/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/FireCloudView.scala index 6bf238bfe6a..70b08b548df 100644 --- a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/FireCloudView.scala +++ b/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/FireCloudView.scala @@ -1,6 +1,6 @@ package org.broadinstitute.dsde.firecloud.page -import org.broadinstitute.dsde.workbench.util.WebBrowserUtil +import org.broadinstitute.dsde.workbench.service.test.WebBrowserUtil import org.openqa.selenium.WebDriver import org.scalatest.selenium.WebBrowser diff --git a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/billing/BillingManagementPage.scala b/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/billing/BillingManagementPage.scala index 4c2f1489ec6..c738c9b5cc1 100644 --- a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/billing/BillingManagementPage.scala +++ b/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/billing/BillingManagementPage.scala @@ -1,8 +1,8 @@ package org.broadinstitute.dsde.firecloud.page.billing -import org.broadinstitute.dsde.firecloud.config.FireCloudConfig +import org.broadinstitute.dsde.workbench.config.{Config => FireCloudConfig} import org.broadinstitute.dsde.firecloud.page.{AuthenticatedPage, FireCloudView, Table} -import org.broadinstitute.dsde.firecloud.util.Retry.retry +import org.broadinstitute.dsde.workbench.service.util.Retry.retry import org.broadinstitute.dsde.workbench.page.PageUtil import org.openqa.selenium.WebDriver import org.scalatest.selenium.Page diff --git a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/library/DataLibraryPage.scala b/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/library/DataLibraryPage.scala index 7cbbf25b2c8..5e8b61658ed 100644 --- a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/library/DataLibraryPage.scala +++ b/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/library/DataLibraryPage.scala @@ -1,6 +1,6 @@ package org.broadinstitute.dsde.firecloud.page.library -import org.broadinstitute.dsde.firecloud.config.FireCloudConfig +import org.broadinstitute.dsde.workbench.config.{Config => FireCloudConfig} import org.broadinstitute.dsde.firecloud.page.AuthenticatedPage import org.broadinstitute.dsde.workbench.page.PageUtil import org.openqa.selenium.WebDriver diff --git a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/methodrepo/MethodDetailPage.scala b/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/methodrepo/MethodDetailPage.scala index 6a209315d99..bca8f71105a 100644 --- a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/methodrepo/MethodDetailPage.scala +++ b/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/methodrepo/MethodDetailPage.scala @@ -1,6 +1,6 @@ package org.broadinstitute.dsde.firecloud.page.methodrepo -import org.broadinstitute.dsde.firecloud.config.FireCloudConfig +import org.broadinstitute.dsde.workbench.config.{Config => FireCloudConfig} import org.broadinstitute.dsde.firecloud.page.{AuthenticatedPage, MessageModal} import org.broadinstitute.dsde.workbench.page.PageUtil import org.openqa.selenium.WebDriver diff --git a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/methodrepo/MethodRepoPage.scala b/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/methodrepo/MethodRepoPage.scala index 92e375ee034..011cee2efcc 100644 --- a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/methodrepo/MethodRepoPage.scala +++ b/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/methodrepo/MethodRepoPage.scala @@ -1,6 +1,6 @@ package org.broadinstitute.dsde.firecloud.page.methodrepo -import org.broadinstitute.dsde.firecloud.config.FireCloudConfig +import org.broadinstitute.dsde.workbench.config.{Config => FireCloudConfig} import org.broadinstitute.dsde.firecloud.page.{AuthenticatedPage, FireCloudView, Table} import org.broadinstitute.dsde.workbench.page.PageUtil import org.openqa.selenium.WebDriver diff --git a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/user/SignInPage.scala b/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/user/SignInPage.scala index 68458a885cf..4538d4e967b 100644 --- a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/user/SignInPage.scala +++ b/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/user/SignInPage.scala @@ -2,7 +2,7 @@ package org.broadinstitute.dsde.firecloud.page.user import org.broadinstitute.dsde.firecloud.page.FireCloudView import org.broadinstitute.dsde.workbench.page.PageUtil -import org.broadinstitute.dsde.workbench.util.WebBrowserUtil +import org.broadinstitute.dsde.workbench.service.test.WebBrowserUtil import org.openqa.selenium.WebDriver import org.scalatest.selenium.{Page, WebBrowser} diff --git a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/workspaces/WorkspaceDataPage.scala b/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/workspaces/WorkspaceDataPage.scala index aa8ccd83988..46fef381711 100644 --- a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/workspaces/WorkspaceDataPage.scala +++ b/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/workspaces/WorkspaceDataPage.scala @@ -1,6 +1,6 @@ package org.broadinstitute.dsde.firecloud.page.workspaces -import org.broadinstitute.dsde.firecloud.config.FireCloudConfig +import org.broadinstitute.dsde.workbench.config.{Config => FireCloudConfig} import org.broadinstitute.dsde.firecloud.page.{FireCloudView, Table} import org.broadinstitute.dsde.workbench.page.PageUtil import org.openqa.selenium.WebDriver diff --git a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/workspaces/WorkspaceListPage.scala b/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/workspaces/WorkspaceListPage.scala index 772bccddc28..9f53e6c02fc 100644 --- a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/workspaces/WorkspaceListPage.scala +++ b/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/workspaces/WorkspaceListPage.scala @@ -1,6 +1,6 @@ package org.broadinstitute.dsde.firecloud.page.workspaces -import org.broadinstitute.dsde.firecloud.config.FireCloudConfig +import org.broadinstitute.dsde.workbench.config.{Config => FireCloudConfig} import org.broadinstitute.dsde.firecloud.page.{AuthenticatedPage, FireCloudView, Table} import org.broadinstitute.dsde.workbench.page.PageUtil import org.openqa.selenium.WebDriver diff --git a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/workspaces/WorkspaceSummaryPage.scala b/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/workspaces/WorkspaceSummaryPage.scala index f1c185a0d40..831c4bead15 100644 --- a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/workspaces/WorkspaceSummaryPage.scala +++ b/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/workspaces/WorkspaceSummaryPage.scala @@ -1,8 +1,8 @@ package org.broadinstitute.dsde.firecloud.page.workspaces -import org.broadinstitute.dsde.firecloud.api.WorkspaceAccessLevel -import org.broadinstitute.dsde.firecloud.api.WorkspaceAccessLevel.WorkspaceAccessLevel -import org.broadinstitute.dsde.firecloud.config.FireCloudConfig +import org.broadinstitute.dsde.workbench.service.WorkspaceAccessLevel +import org.broadinstitute.dsde.workbench.service.WorkspaceAccessLevel.WorkspaceAccessLevel +import org.broadinstitute.dsde.workbench.config.{Config => FireCloudConfig} import org.broadinstitute.dsde.firecloud.page.workspaces.methodconfigs.WorkspaceMethodConfigListPage import org.broadinstitute.dsde.firecloud.page._ import org.broadinstitute.dsde.workbench.page.PageUtil diff --git a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/workspaces/methodconfigs/WorkspaceMethodConfigDetailsPage.scala b/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/workspaces/methodconfigs/WorkspaceMethodConfigDetailsPage.scala index 9b2184b030c..6abf5bd5aa4 100644 --- a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/workspaces/methodconfigs/WorkspaceMethodConfigDetailsPage.scala +++ b/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/workspaces/methodconfigs/WorkspaceMethodConfigDetailsPage.scala @@ -1,6 +1,6 @@ package org.broadinstitute.dsde.firecloud.page.workspaces.methodconfigs -import org.broadinstitute.dsde.firecloud.config.FireCloudConfig +import org.broadinstitute.dsde.workbench.config.{Config => FireCloudConfig} import org.broadinstitute.dsde.firecloud.page.workspaces.WorkspacePage import org.broadinstitute.dsde.firecloud.page.workspaces.monitor.SubmissionDetailsPage import org.broadinstitute.dsde.firecloud.page.{ErrorModal, FireCloudView, Table} diff --git a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/workspaces/methodconfigs/WorkspaceMethodConfigListPage.scala b/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/workspaces/methodconfigs/WorkspaceMethodConfigListPage.scala index e2fea28f68b..cce642045dc 100644 --- a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/workspaces/methodconfigs/WorkspaceMethodConfigListPage.scala +++ b/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/workspaces/methodconfigs/WorkspaceMethodConfigListPage.scala @@ -1,6 +1,6 @@ package org.broadinstitute.dsde.firecloud.page.workspaces.methodconfigs -import org.broadinstitute.dsde.firecloud.config.FireCloudConfig +import org.broadinstitute.dsde.workbench.config.{Config => FireCloudConfig} import org.broadinstitute.dsde.firecloud.page.workspaces.WorkspacePage import org.broadinstitute.dsde.firecloud.page.{FireCloudView, Table} import org.broadinstitute.dsde.workbench.page.PageUtil diff --git a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/workspaces/monitor/SubmissionDetailsPage.scala b/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/workspaces/monitor/SubmissionDetailsPage.scala index bd998560e9a..73e41e97b70 100644 --- a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/workspaces/monitor/SubmissionDetailsPage.scala +++ b/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/workspaces/monitor/SubmissionDetailsPage.scala @@ -1,6 +1,6 @@ package org.broadinstitute.dsde.firecloud.page.workspaces.monitor -import org.broadinstitute.dsde.firecloud.config.FireCloudConfig +import org.broadinstitute.dsde.workbench.config.{Config => FireCloudConfig} import org.broadinstitute.dsde.firecloud.page.workspaces.WorkspacePage import org.broadinstitute.dsde.workbench.page.PageUtil import org.openqa.selenium.WebDriver diff --git a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/workspaces/monitor/WorkspaceMonitorPage.scala b/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/workspaces/monitor/WorkspaceMonitorPage.scala index 601f1f3c8ca..a9e3997fe39 100644 --- a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/workspaces/monitor/WorkspaceMonitorPage.scala +++ b/automation/src/test/scala/org/broadinstitute/dsde/firecloud/page/workspaces/monitor/WorkspaceMonitorPage.scala @@ -1,6 +1,6 @@ package org.broadinstitute.dsde.firecloud.page.workspaces.monitor -import org.broadinstitute.dsde.firecloud.config.FireCloudConfig +import org.broadinstitute.dsde.workbench.config.{Config => FireCloudConfig} import org.broadinstitute.dsde.firecloud.page.workspaces.WorkspacePage import org.broadinstitute.dsde.workbench.page.PageUtil import org.openqa.selenium.WebDriver diff --git a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/util/Retry.scala b/automation/src/test/scala/org/broadinstitute/dsde/firecloud/util/Retry.scala deleted file mode 100644 index 6cee18c1ba5..00000000000 --- a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/util/Retry.scala +++ /dev/null @@ -1,37 +0,0 @@ -package org.broadinstitute.dsde.firecloud.util - -import com.typesafe.scalalogging.LazyLogging - -import scala.concurrent.duration.FiniteDuration - -/** - */ -object Retry extends LazyLogging { - - /** - * Retry an operation periodically until it returns something or no more - * retries remain. Returns when the operation returns Some or all retries - * have been exhausted. - * - * @param remainingBackOffIntervals wait intervals between retries - * @param op operation to retry - * @return the result of the operation - */ - def retry[T](remainingBackOffIntervals: Seq[FiniteDuration])(op: => Option[T]): Option[T] = { - op match { - case Some(x) => Some(x) - case None => remainingBackOffIntervals match { - case Nil => None - case h :: t => - logger.info(s"Retrying: ${remainingBackOffIntervals.size} retries remaining, retrying in $h") - Thread sleep h.toMillis - retry(t)(op) - } - } - } - - def retry[T](interval: FiniteDuration, timeout: FiniteDuration)(op: => Option[T]): Option[T] = { - val iterations = (timeout / interval).round.toInt - retry(Seq.fill(iterations)(interval))(op) - } -} diff --git a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/util/Util.scala b/automation/src/test/scala/org/broadinstitute/dsde/firecloud/util/Util.scala deleted file mode 100644 index e8c80dff6a1..00000000000 --- a/automation/src/test/scala/org/broadinstitute/dsde/firecloud/util/Util.scala +++ /dev/null @@ -1,26 +0,0 @@ -package org.broadinstitute.dsde.firecloud.util - -import java.util.UUID - -import scala.concurrent.duration.FiniteDuration -import scala.util.Random - -/** - */ -object Util { - - def appendUnderscore(string: String): String = { - string match { - case "" => "" - case s => s + "_" - } - } - - def makeRandomId(length: Int = 7): String = { - Random.alphanumeric.take(length).mkString - } - - def makeUuid: String = { - UUID.randomUUID().toString - } -} diff --git a/automation/src/test/scala/org/broadinstitute/dsde/workbench/WebBrowserSpec.scala b/automation/src/test/scala/org/broadinstitute/dsde/workbench/WebBrowserSpec.scala deleted file mode 100644 index 0f2ada77d40..00000000000 --- a/automation/src/test/scala/org/broadinstitute/dsde/workbench/WebBrowserSpec.scala +++ /dev/null @@ -1,139 +0,0 @@ -package org.broadinstitute.dsde.workbench - -import java.io.{File, FileInputStream, FileOutputStream} -import java.net.URL -import java.text.SimpleDateFormat -import java.util.UUID - -import com.typesafe.scalalogging.LazyLogging -import org.broadinstitute.dsde.workbench.config.WorkbenchConfig -import org.broadinstitute.dsde.workbench.util.{ExceptionHandling, WebBrowserUtil} -import org.openqa.selenium.chrome.{ChromeDriverService, ChromeOptions} -import org.openqa.selenium.remote.{Augmenter, DesiredCapabilities, LocalFileDetector, RemoteWebDriver} -import org.openqa.selenium.{OutputType, TakesScreenshot, WebDriver} -import org.scalatest.Suite - -import scala.collection.JavaConverters._ -import scala.sys.SystemProperties -import scala.util.Random - -/** - * Base spec for writing web browser tests. - */ -trait WebBrowserSpec extends WebBrowserUtil with ExceptionHandling with LazyLogging { self: Suite => - - /** - * Executes a test in a fixture with a managed WebDriver. A test that uses - * this will get its own WebDriver instance will be destroyed when the test - * is complete. This encourages test case isolation. - * - * @param testCode the test code to run - */ - def withWebDriver(testCode: (WebDriver) => Any): Unit = { - withWebDriver(System.getProperty("java.io.tmpdir"))(testCode) - } - - /** - * Executes a test in a fixture with a managed WebDriver. A test that uses - * this will get its own WebDriver instance will be destroyed when the test - * is complete. This encourages test case isolation. - * - * @param downloadPath a directory where downloads should be saved - * @param testCode the test code to run - */ - def withWebDriver(downloadPath: String)(testCode: (WebDriver) => Any): Unit = { - val capabilities = getChromeIncognitoOption(downloadPath) - val headless = new SystemProperties().get("headless") - headless match { - case Some("false") => runLocalChrome(capabilities, testCode) - case _ => runHeadless(capabilities, testCode) - } - } - - private def getChromeIncognitoOption(downloadPath: String): DesiredCapabilities = { - val options = new ChromeOptions - options.addArguments("--incognito") - // Note that download.prompt_for_download will be ignored if download.default_directory is invalid or doesn't exist - options.setExperimentalOption("prefs", Map( - "download.default_directory" -> downloadPath, - "download.prompt_for_download" -> "false").asJava) - val capabilities = DesiredCapabilities.chrome - capabilities.setCapability(ChromeOptions.CAPABILITY, options) - capabilities - } - - private def runLocalChrome(capabilities: DesiredCapabilities, testCode: (WebDriver) => Any): Unit = { - val service = new ChromeDriverService.Builder().usingDriverExecutable(new File(WorkbenchConfig.ChromeSettings.chromDriverPath)).usingAnyFreePort().build() - service.start() - implicit val driver: RemoteWebDriver = new RemoteWebDriver(service.getUrl, capabilities) -// driver.manage.window.setSize(new org.openqa.selenium.Dimension(1600, 2400)) - driver.setFileDetector(new LocalFileDetector()) - try { - withScreenshot { - testCode(driver) - } - } finally { - try driver.quit() catch nonFatalAndLog - try service.stop() catch nonFatalAndLog - } - } - - private def runHeadless(capabilities: DesiredCapabilities, testCode: (WebDriver) => Any): Unit = { - val defaultChrome = WorkbenchConfig.ChromeSettings.chromedriverHost - implicit val driver: RemoteWebDriver = new RemoteWebDriver(new URL(defaultChrome), capabilities) -// driver.manage.window.setSize(new org.openqa.selenium.Dimension(1600, 2400)) - driver.setFileDetector(new LocalFileDetector()) - try { - withScreenshot { - testCode(driver) - } - } finally { - try driver.quit() catch nonFatalAndLog - } - } - - - /** - * Make a random alpha-numeric (lowercase) string to be used as a semi-unique - * identifier. - * - * @param length the number of characters in the string - * @return a random string - */ - def makeRandomId(length: Int = 7): String = { - Random.alphanumeric.take(length).mkString.toLowerCase - } - - def randomUuid: String = { - UUID.randomUUID().toString - } - - /** - * Override of withScreenshot that works with a remote Chrome driver and - * lets us control the image file name. - */ - override def withScreenshot(f: => Unit)(implicit driver: WebDriver): Unit = { - try { - f - } catch { - case t: Throwable => - val date = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss-SSS").format(new java.util.Date()) - val fileName = s"failure_screenshots/${date}_$suiteName.png" - val htmlSourceFileName = s"failure_screenshots/${date}_$suiteName.html" - try { - val directory = new File("failure_screenshots") - if (!directory.exists()) { - directory.mkdir() - } - val tmpFile = new Augmenter().augment(driver).asInstanceOf[TakesScreenshot].getScreenshotAs(OutputType.FILE) - logger.error(s"Failure screenshot saved to $fileName") - new FileOutputStream(new File(fileName)).getChannel.transferFrom( - new FileInputStream(tmpFile).getChannel, 0, Long.MaxValue) - - val html = tagName("html").element.underlying.getAttribute("outerHTML") - new FileOutputStream(new File(htmlSourceFileName)).write(html.getBytes) - } catch nonFatalAndLog(s"FAILED TO SAVE SCREENSHOT $fileName") - throw t - } - } -} diff --git a/automation/src/test/scala/org/broadinstitute/dsde/workbench/api/APIException.scala b/automation/src/test/scala/org/broadinstitute/dsde/workbench/api/APIException.scala deleted file mode 100644 index bcb22233030..00000000000 --- a/automation/src/test/scala/org/broadinstitute/dsde/workbench/api/APIException.scala +++ /dev/null @@ -1,3 +0,0 @@ -package org.broadinstitute.dsde.workbench.api - -case class APIException (message: String = null, cause: Throwable = null) extends Exception(message, cause) diff --git a/automation/src/test/scala/org/broadinstitute/dsde/workbench/api/WorkbenchClient.scala b/automation/src/test/scala/org/broadinstitute/dsde/workbench/api/WorkbenchClient.scala deleted file mode 100644 index 89e2a461654..00000000000 --- a/automation/src/test/scala/org/broadinstitute/dsde/workbench/api/WorkbenchClient.scala +++ /dev/null @@ -1,118 +0,0 @@ -package org.broadinstitute.dsde.workbench.api - -import akka.actor.ActorSystem -import akka.http.scaladsl.Http -import akka.http.scaladsl.model.HttpMethods._ -import akka.http.scaladsl.model.headers.{Authorization, OAuth2BearerToken} -import akka.http.scaladsl.model._ -import akka.stream.ActorMaterializer -import akka.stream.scaladsl._ -import akka.util.ByteString -import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.module.scala.DefaultScalaModule -import org.broadinstitute.dsde.workbench.config.AuthToken - -import scala.concurrent.duration._ -import scala.concurrent.{Await, ExecutionContextExecutor, Future} - -trait WorkbenchClient { - implicit val system = ActorSystem() - implicit val materializer = ActorMaterializer() - implicit val ec: ExecutionContextExecutor = system.dispatcher - - val awaitResponseDuration = 1.second - - val mapper = new ObjectMapper() - mapper.registerModule(DefaultScalaModule) - - implicit protected class JsonStringUtil(s: String) { - def fromJsonMapAs[A](key: String): Option[A] = parseJsonAsMap.get(key) - def parseJsonAsMap[A]: Map[String, A] = mapper.readValue(s, classOf[Map[String, A]]) - } - - private def makeAuthHeader(token: AuthToken): Authorization = { - headers.Authorization(OAuth2BearerToken(token.value)) - } - - private def sendRequest(httpRequest: HttpRequest): HttpResponse = { - Await.result(Http().singleRequest(httpRequest), 5.minutes) - } - - private def handleResponse(response: HttpResponse): String = { - response.status.isSuccess() match { - case true => - val byteStringSink: Sink[ByteString, Future[ByteString]] = Sink.fold(ByteString("")) { (z, i) => z.concat(i) } - val entityFuture = response.entity.dataBytes.runWith(byteStringSink) - Await.result(entityFuture, awaitResponseDuration).decodeString("UTF-8") - case _ => - val byteStringSink: Sink[ByteString, Future[ByteString]] = Sink.fold(ByteString("")) { (z, i) => z.concat(i) } - val entityFuture = response.entity.dataBytes.runWith(byteStringSink) - throw APIException(Await.result(entityFuture, awaitResponseDuration).decodeString("UTF-8")) - } - } - - def parseResponse(response: HttpResponse): String = { - response.status.isSuccess() match { - case true => - val byteStringSink: Sink[ByteString, Future[ByteString]] = Sink.fold(ByteString("")) { (z, i) => z.concat(i) } - val entityFuture = response.entity.dataBytes.runWith(byteStringSink) - Await.result(entityFuture, awaitResponseDuration).decodeString("UTF-8") - case _ => - val byteStringSink: Sink[ByteString, Future[ByteString]] = Sink.fold(ByteString("")) { (z, i) => z.concat(i) } - val entityFuture = response.entity.dataBytes.runWith(byteStringSink) - throw APIException(Await.result(entityFuture, awaitResponseDuration).decodeString("UTF-8")) - } - } - - import scala.reflect.{ClassTag, classTag} - def parseResponseAs[T: ClassTag](response: HttpResponse): T = { - // https://stackoverflow.com/questions/6200253/scala-classof-for-type-parameter - val classT: Class[T] = classTag[T].runtimeClass.asInstanceOf[Class[T]] - mapper.readValue(parseResponse(response), classT) - } - - // return Some(T) on success, None on failure - def parseResponseOption[T: ClassTag](response: HttpResponse): Option[T] = { - if (response.status.isSuccess()) - Option(parseResponseAs[T](response)) - else - None - } - - private def requestWithJsonContent(method: HttpMethod, uri: String, content: Any, httpHeaders: List[HttpHeader] = List())(implicit token: AuthToken): String = { - val req = HttpRequest(method, uri, List(makeAuthHeader(token)) ++ httpHeaders, HttpEntity(ContentTypes.`application/json`, mapper.writeValueAsString(content))) - handleResponse(sendRequest(req)) - } - - def postRequestWithMultipart(uri:String, name: String, content: String)(implicit token: AuthToken): String = { - val part = Multipart.FormData.BodyPart(name, HttpEntity(ByteString(content))) - val formData = Multipart.FormData(Source.single(part)) - val req = HttpRequest(POST, uri, List(makeAuthHeader(token)), formData.toEntity()) - handleResponse(sendRequest(req)) - } - - private def requestBasic(method: HttpMethod, uri: String, httpHeaders: List[HttpHeader] = List())(implicit token: AuthToken): HttpResponse = { - val req = HttpRequest(method, uri, List(makeAuthHeader(token)) ++ httpHeaders) - sendRequest(req) - } - - def patchRequest(uri: String, content: Any, httpHeaders: List[HttpHeader] = List())(implicit token: AuthToken): String = { - requestWithJsonContent(PATCH, uri, content, httpHeaders) - } - - def postRequest(uri: String, content: Any = None, httpHeaders: List[HttpHeader] = List())(implicit token: AuthToken): String = { - requestWithJsonContent(POST, uri, content, httpHeaders) - } - - def putRequest(uri: String, content: Any = None, httpHeaders: List[HttpHeader] = List())(implicit token: AuthToken): String = { - requestWithJsonContent(PUT, uri, content, httpHeaders) - } - - def deleteRequest(uri: String, httpHeaders: List[HttpHeader] = List())(implicit token: AuthToken): String = { - handleResponse(requestBasic(DELETE, uri, httpHeaders)) - } - - def getRequest(uri: String, httpHeaders: List[HttpHeader] = List())(implicit token: AuthToken): HttpResponse = { - requestBasic(GET, uri, httpHeaders) - } -} diff --git a/automation/src/test/scala/org/broadinstitute/dsde/workbench/config/AuthTokens.scala b/automation/src/test/scala/org/broadinstitute/dsde/workbench/config/AuthTokens.scala deleted file mode 100644 index 80c8482defb..00000000000 --- a/automation/src/test/scala/org/broadinstitute/dsde/workbench/config/AuthTokens.scala +++ /dev/null @@ -1,57 +0,0 @@ -package org.broadinstitute.dsde.workbench.config - -import com.google.api.client.googleapis.auth.oauth2.GoogleCredential -import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport -import com.google.api.client.json.jackson2.JacksonFactory - -import scala.collection.JavaConverters._ - -object AuthTokens { - val dumbledore = AuthToken(WorkbenchConfig.Users.dumbledore) - val admin = dumbledore - val hermione = AuthToken(WorkbenchConfig.Users.hermione) - val owner = hermione - val mcgonagall = AuthToken(WorkbenchConfig.Users.mcgonagall) - val curator = mcgonagall - val harry = AuthToken(WorkbenchConfig.Users.harry) - val testUser = harry - val dominique = harry - val fred = AuthToken(WorkbenchConfig.Users.fred) - val elvin = fred - val george = AuthToken(WorkbenchConfig.Users.george) - val bill = AuthToken(WorkbenchConfig.Users.bill) - val lunaTemp = AuthToken(WorkbenchConfig.Users.lunaTemp) - val nevilleTemp = AuthToken(WorkbenchConfig.Users.nevilleTemp) -} - -case class AuthToken(value: String) - -case object AuthToken { - def apply(user: Credentials): AuthToken = getUserToken(user.email) - - val httpTransport = GoogleNetHttpTransport.newTrustedTransport - val jsonFactory = JacksonFactory.getDefaultInstance - val authScopes = Seq("profile", "email", "openid", "https://www.googleapis.com/auth/devstorage.full_control", "https://www.googleapis.com/auth/cloud-platform") - - def getUserToken(userEmail: String): AuthToken = { - val cred = buildCredential(userEmail) - cred.refreshToken() - AuthToken(cred.getAccessToken) - } - - def buildCredential(userEmail: String): GoogleCredential = { - val pemfile = new java.io.File(WorkbenchConfig.GCS.pathToQAPem) - val email = WorkbenchConfig.GCS.qaEmail - - new GoogleCredential.Builder() - .setTransport(httpTransport) - .setJsonFactory(jsonFactory) - .setServiceAccountId(email) - .setServiceAccountPrivateKeyFromPemFile(pemfile) - .setServiceAccountScopes(authScopes.asJava) - .setServiceAccountUser(userEmail) - .build() - } -} - - diff --git a/automation/src/test/scala/org/broadinstitute/dsde/workbench/config/Credentials.scala b/automation/src/test/scala/org/broadinstitute/dsde/workbench/config/Credentials.scala deleted file mode 100644 index 2f295b6b8c4..00000000000 --- a/automation/src/test/scala/org/broadinstitute/dsde/workbench/config/Credentials.scala +++ /dev/null @@ -1,4 +0,0 @@ -package org.broadinstitute.dsde.workbench.config - -case class Credentials (email: String, password: String) - diff --git a/automation/src/test/scala/org/broadinstitute/dsde/workbench/config/LeoAuthToken.scala b/automation/src/test/scala/org/broadinstitute/dsde/workbench/config/LeoAuthToken.scala new file mode 100644 index 00000000000..741d823104b --- /dev/null +++ b/automation/src/test/scala/org/broadinstitute/dsde/workbench/config/LeoAuthToken.scala @@ -0,0 +1,53 @@ +package org.broadinstitute.dsde.workbench.config + +import com.google.api.client.googleapis.auth.oauth2.GoogleCredential +import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport +import com.google.api.client.json.jackson2.JacksonFactory +import org.broadinstitute.dsde.workbench.auth.AuthToken + +import scala.collection.JavaConverters._ + +case class LeoAuthToken(value: String) + +case object LeoAuthToken extends AuthToken { + def apply(user: Credentials): LeoAuthToken = getUserToken(user.email) + + override val httpTransport = GoogleNetHttpTransport.newTrustedTransport + override val jsonFactory = JacksonFactory.getDefaultInstance + override val authScopes = Seq("profile", "email", "openid", "https://www.googleapis.com/auth/devstorage.full_control", "https://www.googleapis.com/auth/cloud-platform") + + def getUserToken(userEmail: String): LeoAuthToken = { + val cred = buildCredential(userEmail) + cred.refreshToken() + LeoAuthToken(cred.getAccessToken) + } + + override def buildCredential(): GoogleCredential = { + val pemfile = new java.io.File(Config.GCS.pathToQAPem) + val email = Config.GCS.qaEmail + + new GoogleCredential.Builder() + .setTransport(httpTransport) + .setJsonFactory(jsonFactory) + .setServiceAccountId(email) + .setServiceAccountPrivateKeyFromPemFile(pemfile) + .setServiceAccountScopes(authScopes.asJava) + .setServiceAccountUser(email) + .build() + } + + def buildCredential(userEmail: String): GoogleCredential = { + val pemfile = new java.io.File(Config.GCS.pathToQAPem) + val email = Config.GCS.qaEmail + + new GoogleCredential.Builder() + .setTransport(httpTransport) + .setJsonFactory(jsonFactory) + .setServiceAccountId(email) + .setServiceAccountPrivateKeyFromPemFile(pemfile) + .setServiceAccountScopes(authScopes.asJava) + .setServiceAccountUser(userEmail) + .build() + } +} + diff --git a/automation/src/test/scala/org/broadinstitute/dsde/workbench/config/WorkbenchConfig.scala b/automation/src/test/scala/org/broadinstitute/dsde/workbench/config/WorkbenchConfig.scala deleted file mode 100644 index ba2216fb1fd..00000000000 --- a/automation/src/test/scala/org/broadinstitute/dsde/workbench/config/WorkbenchConfig.scala +++ /dev/null @@ -1,61 +0,0 @@ -package org.broadinstitute.dsde.workbench.config - -import com.typesafe.config.ConfigFactory - -object WorkbenchConfig extends WorkbenchConfig - -trait WorkbenchConfig { - protected val config = ConfigFactory.load() - - private val users = config.getConfig("users") - private val chromeSettings = config.getConfig("chromeSettings") - private val gcsConfig = config.getConfig("gcs") - - object GCS { - val pathToQAPem = gcsConfig.getString("qaPemFile") - val qaEmail = gcsConfig.getString("qaEmail") - val appsDomain = gcsConfig.getString("appsDomain") - } - - object Projects { - val default = gcsConfig.getString("serviceProject") - val common = default - val billingAccount = gcsConfig.getString("billingAccount") - val billingAccountId = gcsConfig.getString("billingAccountId") - } - - object Users { - val notSoSecretPassword = users.getString("notSoSecretPassword") - - val dumbledore = Credentials(users.getString("dumbledore"), notSoSecretPassword) - val voldemort = Credentials(users.getString("voldemort"), notSoSecretPassword) - val admin = dumbledore - - val hermione = Credentials(users.getString("hermione"), notSoSecretPassword) - val owner = hermione - - val mcgonagall = Credentials(users.getString("mcgonagall"), notSoSecretPassword) - val snape = Credentials(users.getString("snape"), notSoSecretPassword) - val curator = mcgonagall - - val harry = Credentials(users.getString("harry"), notSoSecretPassword) - val ron = Credentials(users.getString("ron"), notSoSecretPassword) - val draco = Credentials(users.getString("draco"), notSoSecretPassword) - - val fred = Credentials(users.getString("fred"), notSoSecretPassword) - val george = Credentials(users.getString("george"), notSoSecretPassword) - val bill = Credentials(users.getString("bill"), notSoSecretPassword) - - val lunaTemp = Credentials(users.getString("luna"), notSoSecretPassword) - val lunaTempSubjectId = users.getString("lunaSubjectId") - val nevilleTemp = Credentials(users.getString("neville"), notSoSecretPassword) - val testUser = harry - val dominique = harry - val elvin = fred - } - - object ChromeSettings { - val chromedriverHost = chromeSettings.getString("chromedriverHost") - val chromDriverPath = chromeSettings.getString("chromedriverPath") - } -} diff --git a/automation/src/test/scala/org/broadinstitute/dsde/workbench/dao/Google.scala b/automation/src/test/scala/org/broadinstitute/dsde/workbench/dao/Google.scala deleted file mode 100644 index 0a5c5a6fce5..00000000000 --- a/automation/src/test/scala/org/broadinstitute/dsde/workbench/dao/Google.scala +++ /dev/null @@ -1,16 +0,0 @@ -package org.broadinstitute.dsde.workbench.dao - -import akka.actor.ActorSystem -import org.broadinstitute.dsde.workbench.config.WorkbenchConfig -import org.broadinstitute.dsde.workbench.google.HttpGoogleIamDAO - -import scala.concurrent.{ExecutionContext, ExecutionContextExecutor} - -object Google { - val appName = "automation" - val metricBaseName = appName - lazy val system = ActorSystem() - val ec: ExecutionContextExecutor = ExecutionContext.global - - lazy val googleIamDAO = new HttpGoogleIamDAO(WorkbenchConfig.GCS.qaEmail, WorkbenchConfig.GCS.pathToQAPem, appName, metricBaseName)(system, ec) -} \ No newline at end of file diff --git a/automation/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/ClusterMonitoringSpec.scala b/automation/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/ClusterMonitoringSpec.scala index f85a63c4072..ab40dc002b9 100644 --- a/automation/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/ClusterMonitoringSpec.scala +++ b/automation/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/ClusterMonitoringSpec.scala @@ -1,13 +1,11 @@ package org.broadinstitute.dsde.workbench.leonardo -import org.broadinstitute.dsde.firecloud.api.Orchestration +import org.broadinstitute.dsde.workbench.service.Orchestration import org.broadinstitute.dsde.workbench.dao.Google.googleIamDAO import org.scalatest.{FreeSpec, ParallelTestExecution} import org.scalatest.time.{Seconds, Span} class ClusterMonitoringSpec extends FreeSpec with LeonardoTestUtils with ParallelTestExecution { - implicit override val patienceConfig: PatienceConfig = PatienceConfig(timeout = scaled(Span(5, Seconds))) - "Leonardo clusters" - { "should create, monitor, and delete a cluster" in { @@ -53,6 +51,7 @@ class ClusterMonitoringSpec extends FreeSpec with LeonardoTestUtils with Paralle // Post-conditions: pet should still exist in this Google project + implicit val patienceConfig: PatienceConfig = saPatience val googlePetEmail2 = googleIamDAO.findServiceAccount(project, petName).futureValue.map(_.email) googlePetEmail2 shouldBe Some(petEmail) } diff --git a/automation/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/DummyClientPage.scala b/automation/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/DummyClientPage.scala index f9c073776fb..f8ede42ed67 100644 --- a/automation/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/DummyClientPage.scala +++ b/automation/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/DummyClientPage.scala @@ -1,8 +1,8 @@ package org.broadinstitute.dsde.workbench.leonardo -import org.broadinstitute.dsde.workbench.config.AuthToken +import org.broadinstitute.dsde.workbench.auth.AuthToken import org.broadinstitute.dsde.workbench.page.PageUtil -import org.broadinstitute.dsde.workbench.util.WebBrowserUtil +import org.broadinstitute.dsde.workbench.service.test.WebBrowserUtil import org.openqa.selenium.WebDriver import org.scalatest.selenium.Page diff --git a/automation/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/Leonardo.scala b/automation/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/Leonardo.scala index 794d07068db..a0f7563e914 100644 --- a/automation/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/Leonardo.scala +++ b/automation/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/Leonardo.scala @@ -7,8 +7,9 @@ import java.util.UUID import akka.http.scaladsl.model.headers.{Cookie, HttpCookiePair} import com.typesafe.scalalogging.LazyLogging import org.broadinstitute.dsde.workbench.ResourceFile -import org.broadinstitute.dsde.workbench.api.WorkbenchClient -import org.broadinstitute.dsde.workbench.config.AuthToken +import org.broadinstitute.dsde.workbench.service.RestClient +import org.broadinstitute.dsde.workbench.auth.AuthToken +import org.broadinstitute.dsde.workbench.config.LeoAuthToken import org.broadinstitute.dsde.workbench.leonardo.StringValueClass.LabelMap import org.broadinstitute.dsde.workbench.model.WorkbenchEmail import org.broadinstitute.dsde.workbench.model.google.GoogleProject @@ -21,7 +22,7 @@ import scala.io.Source /** * Leonardo API service client. */ -object Leonardo extends WorkbenchClient with LazyLogging { +object Leonardo extends RestClient with LazyLogging { private val url = LeonardoConfig.Leonardo.apiUrl @@ -177,13 +178,13 @@ object Leonardo extends WorkbenchClient with LazyLogging { parameter('token.as[String]) { token => complete { logger.info(s"Serving dummy client for $googleProject/$clusterName") - HttpEntity(ContentTypes.`text/html(UTF-8)`, getContent(GoogleProject(googleProject), ClusterName(clusterName), AuthToken(token))) + HttpEntity(ContentTypes.`text/html(UTF-8)`, getContent(GoogleProject(googleProject), ClusterName(clusterName), LeoAuthToken(token))) } } } } - private def getContent(googleProject: GoogleProject, clusterName: ClusterName, token: AuthToken) = { + private def getContent(googleProject: GoogleProject, clusterName: ClusterName, token: LeoAuthToken) = { val resourceFile = ResourceFile("dummy-notebook-client.html") val raw = Source.fromFile(resourceFile).mkString val replacementMap = Map( diff --git a/automation/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/LeonardoConfig.scala b/automation/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/LeonardoConfig.scala index 062821d7f84..c2debb73904 100644 --- a/automation/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/LeonardoConfig.scala +++ b/automation/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/LeonardoConfig.scala @@ -1,9 +1,9 @@ package org.broadinstitute.dsde.workbench.leonardo -import org.broadinstitute.dsde.workbench.config.WorkbenchConfig +import org.broadinstitute.dsde.workbench.config.Config -object LeonardoConfig extends WorkbenchConfig { - private val leonardo = config.getConfig("leonardo") +object LeonardoConfig extends Config { + private val leonardo = Config.config.getConfig("leonardo") object Leonardo { val apiUrl: String = leonardo.getString("apiUrl") diff --git a/automation/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/LeonardoTestUtils.scala b/automation/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/LeonardoTestUtils.scala index fd072bbd335..9a8e4f43cf2 100644 --- a/automation/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/LeonardoTestUtils.scala +++ b/automation/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/LeonardoTestUtils.scala @@ -4,11 +4,12 @@ import java.io.File import java.nio.file.Files import com.typesafe.scalalogging.LazyLogging -import org.broadinstitute.dsde.firecloud.api.{Orchestration, Rawls, Sam} -import org.broadinstitute.dsde.workbench.WebBrowserSpec -import org.broadinstitute.dsde.workbench.api.APIException -import org.broadinstitute.dsde.workbench.config.{AuthToken, WorkbenchConfig} import org.broadinstitute.dsde.workbench.dao.Google.googleIamDAO +import org.broadinstitute.dsde.workbench.auth.{AuthToken, UserAuthToken} +import org.broadinstitute.dsde.workbench.config.{Config, Credentials, LeoAuthToken} +import org.broadinstitute.dsde.workbench.service.{Orchestration, Rawls, Sam} +import org.broadinstitute.dsde.workbench.service.APIException +import org.broadinstitute.dsde.workbench.service.test.WebBrowserSpec import org.broadinstitute.dsde.workbench.leonardo.ClusterStatus.ClusterStatus import org.broadinstitute.dsde.workbench.leonardo.StringValueClass.LabelMap import org.broadinstitute.dsde.workbench.model.WorkbenchEmail @@ -28,13 +29,17 @@ trait LeonardoTestUtils extends WebBrowserSpec with Matchers with Eventually wit val swatTestBucket = "gs://leonardo-swat-test-bucket-do-not-delete" val incorrectJupyterExtensionUri = swatTestBucket + "/" - // Ron and Hermione are on the dev Leo whitelist. - val ronAuthToken = AuthToken(LeonardoConfig.Users.ron) - val hermioneAuthToken = AuthToken(LeonardoConfig.Users.hermione) - val ronEmail = LeonardoConfig.Users.ron.email + // Ron and Hermione are on the dev Leo whitelist, and Hermione is a Project Owner + lazy val ronCreds: Credentials = Config.Users.NotebooksWhitelisted.getUserCredential("ron") + lazy val hermioneCreds: Credentials = Config.Users.NotebooksWhitelisted.getUserCredential("hermione") + + lazy val ronAuthToken = UserAuthToken(ronCreds) + lazy val hermioneAuthToken = UserAuthToken(hermioneCreds) + lazy val ronEmail = ronCreds.email val clusterPatience = PatienceConfig(timeout = scaled(Span(15, Minutes)), interval = scaled(Span(20, Seconds))) val localizePatience = PatienceConfig(timeout = scaled(Span(1, Minutes)), interval = scaled(Span(1, Seconds))) + val saPatience = PatienceConfig(timeout = scaled(Span(1, Minutes)), interval = scaled(Span(1, Seconds))) // TODO: show diffs as screenshot or other test output? def compareFilesExcludingIPs(left: File, right: File): Unit = { @@ -52,13 +57,13 @@ trait LeonardoTestUtils extends WebBrowserSpec with Matchers with Eventually wit val billingProject = "leonardo-billing-spec-" + makeRandomId() logger.info(s"Creating billing project: $billingProject") - Orchestration.billing.createBillingProject(billingProject, WorkbenchConfig.Projects.billingAccountId)(ownerToken) + Orchestration.billing.createBillingProject(billingProject, Config.Projects.billingAccountId)(ownerToken) GoogleProject(billingProject) } def cleanupBillingProject(billingProject: GoogleProject): Unit = { - Try(Rawls.admin.deleteBillingProject(billingProject.value)(AuthToken(LeonardoConfig.Users.dumbledore))).recover { case NonFatal(e) => + Try(Rawls.admin.deleteBillingProject(billingProject.value)(UserAuthToken(Config.Users.Admins.getUserCredential("dumbledore")))).recover { case NonFatal(e) => logger.warn(s"Could not delete billing project $billingProject", e) } } @@ -119,9 +124,10 @@ trait LeonardoTestUtils extends WebBrowserSpec with Matchers with Eventually wit clusterCheck(Leonardo.cluster.get(googleProject, clusterName), clusterRequest.labels, googleProject, clusterName, Seq(ClusterStatus.Creating), clusterRequest.jupyterExtensionUri) // wait for "Running" or error (fail fast) + implicit val patienceConfig: PatienceConfig = clusterPatience val actualCluster = eventually { clusterCheck(Leonardo.cluster.get(googleProject, clusterName), clusterRequest.labels, googleProject, clusterName, Seq(ClusterStatus.Running, ClusterStatus.Error), clusterRequest.jupyterExtensionUri) - } (clusterPatience) + } actualCluster } @@ -138,10 +144,11 @@ trait LeonardoTestUtils extends WebBrowserSpec with Matchers with Eventually wit } // wait until not found or in "Deleted" state + implicit val patienceConfig: PatienceConfig = clusterPatience eventually { val statusOpt = Leonardo.cluster.listIncludingDeleted().find(_.clusterName == clusterName).map(_.status) statusOpt getOrElse ClusterStatus.Deleted shouldBe ClusterStatus.Deleted - } (clusterPatience) + } } def createNewCluster(googleProject: GoogleProject)(implicit token: AuthToken): Cluster = { @@ -191,9 +198,10 @@ trait LeonardoTestUtils extends WebBrowserSpec with Matchers with Eventually wit } def getAndVerifyPet(project: GoogleProject)(implicit token: AuthToken): (ServiceAccountName, WorkbenchEmail) = { - val samPetEmail = Sam.user.petServiceAccountEmail(project) + val samPetEmail = Sam.user.petServiceAccountEmail(project.value) val userStatus = Sam.user.status().get val petName = Sam.petName(userStatus.userInfo) + implicit val patienceConfig: PatienceConfig = saPatience val googlePetEmail = googleIamDAO.findServiceAccount(project, petName).futureValue.map(_.email) googlePetEmail shouldBe Some(samPetEmail) (petName, samPetEmail) diff --git a/automation/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/NotebookInteractionSpec.scala b/automation/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/NotebookInteractionSpec.scala index 1497dee098e..644f0b63059 100644 --- a/automation/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/NotebookInteractionSpec.scala +++ b/automation/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/NotebookInteractionSpec.scala @@ -3,16 +3,15 @@ package org.broadinstitute.dsde.workbench.leonardo import java.io.File import java.time.Instant -import org.broadinstitute.dsde.firecloud.api.Orchestration +import org.broadinstitute.dsde.workbench.service.Orchestration import org.broadinstitute.dsde.workbench.ResourceFile -import org.broadinstitute.dsde.workbench.config.AuthToken +import org.broadinstitute.dsde.workbench.auth.AuthToken +import org.broadinstitute.dsde.workbench.config.Config import org.broadinstitute.dsde.workbench.model.google.GoogleProject import org.scalatest.time.{Seconds, Span} import org.scalatest.{BeforeAndAfterAll, FreeSpec} class NotebookInteractionSpec extends FreeSpec with LeonardoTestUtils with BeforeAndAfterAll { - implicit override val patienceConfig: PatienceConfig = PatienceConfig(timeout = scaled(Span(5, Seconds))) - /* * This class creates a cluster in a new billing project and runs all tests inside the same cluster. */ @@ -84,11 +83,12 @@ class NotebookInteractionSpec extends FreeSpec with LeonardoTestUtils with Befor //"gs://new_bucket/import-hail.ipynb" -> "import-hail.ipynb" ) + implicit val patienceConfig: PatienceConfig = localizePatience eventually { Leonardo.notebooks.localize(ronCluster.googleProject, ronCluster.clusterName, goodLocalize) //the following line will barf with an exception if the file isn't there; that's enough Leonardo.notebooks.getContentItem(ronCluster.googleProject, ronCluster.clusterName, "test.rtf", includeContent = false) - }(localizePatience) + } val localizationLog = Leonardo.notebooks.getContentItem(ronCluster.googleProject, ronCluster.clusterName, "localization.log") @@ -134,7 +134,6 @@ class NotebookInteractionSpec extends FreeSpec with LeonardoTestUtils with Befor "should allow BigQuerying in a new billing project" in withWebDriver { implicit driver => // project owners have the bigquery role automatically, so this also tests granting it to users - val ronEmail = LeonardoConfig.Users.ron.email val ownerToken = hermioneAuthToken Orchestration.billing.addGoogleRoleToBillingProjectUser(billingProject.value, ronEmail, "bigquery.jobUser")(ownerToken) diff --git a/automation/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/NotebookPage.scala b/automation/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/NotebookPage.scala index 97c143a8af9..1e6ae738c46 100644 --- a/automation/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/NotebookPage.scala +++ b/automation/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/NotebookPage.scala @@ -1,7 +1,7 @@ package org.broadinstitute.dsde.workbench.leonardo import org.apache.commons.text.StringEscapeUtils -import org.broadinstitute.dsde.workbench.config.AuthToken +import org.broadinstitute.dsde.workbench.auth.AuthToken import org.openqa.selenium.{By, WebDriver, WebElement} import org.openqa.selenium.interactions.Actions diff --git a/automation/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/NotebooksListPage.scala b/automation/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/NotebooksListPage.scala index 45f625158d7..91517b154a8 100644 --- a/automation/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/NotebooksListPage.scala +++ b/automation/src/test/scala/org/broadinstitute/dsde/workbench/leonardo/NotebooksListPage.scala @@ -2,7 +2,7 @@ package org.broadinstitute.dsde.workbench.leonardo import java.io.File -import org.broadinstitute.dsde.workbench.config.AuthToken +import org.broadinstitute.dsde.workbench.auth.AuthToken import org.openqa.selenium.WebDriver import scala.util.Try diff --git a/automation/src/test/scala/org/broadinstitute/dsde/workbench/page/CookieAuthedPage.scala b/automation/src/test/scala/org/broadinstitute/dsde/workbench/page/CookieAuthedPage.scala index c371270beec..a90cb2bbbf4 100644 --- a/automation/src/test/scala/org/broadinstitute/dsde/workbench/page/CookieAuthedPage.scala +++ b/automation/src/test/scala/org/broadinstitute/dsde/workbench/page/CookieAuthedPage.scala @@ -1,7 +1,7 @@ package org.broadinstitute.dsde.workbench.page -import org.broadinstitute.dsde.workbench.config.AuthToken -import org.broadinstitute.dsde.workbench.util.WebBrowserUtil +import org.broadinstitute.dsde.workbench.auth.AuthToken +import org.broadinstitute.dsde.workbench.service.test.WebBrowserUtil import org.openqa.selenium.WebDriver import org.scalatest.selenium.Page diff --git a/automation/src/test/scala/org/broadinstitute/dsde/workbench/util/ExceptionHandling.scala b/automation/src/test/scala/org/broadinstitute/dsde/workbench/util/ExceptionHandling.scala deleted file mode 100644 index 60bf7171cee..00000000000 --- a/automation/src/test/scala/org/broadinstitute/dsde/workbench/util/ExceptionHandling.scala +++ /dev/null @@ -1,36 +0,0 @@ -package org.broadinstitute.dsde.workbench.util - -import com.typesafe.scalalogging.LazyLogging - -import scala.util.control.NonFatal - -/** - */ -//trait ExceptionHandling { self: LazyLogging => -trait ExceptionHandling extends LazyLogging { - /** - * Return a partial function that logs and suppresses any "non-fatal" - * exceptions. To be used liberally during test clean-up operations to - * avoid overshadowing exceptions and failures from the test itself: - * - *
-    *   try cleanUp() catch nonFatalAndLog
-    * 
- */ - def nonFatalAndLog: PartialFunction[Throwable, Unit] = { - case NonFatal(e) => logger.warn(e.getMessage) - } - - /** - * Return a partial function that logs and suppresses any "non-fatal" - * exceptions. To be used liberally during test clean-up operations to - * avoid overshadowing exceptions and failures from the test itself: - * - *
-    *   try cleanUp() catch nonFatalAndLog("Oops")
-    * 
- */ - def nonFatalAndLog(message: String): PartialFunction[Throwable, Unit] = { - case NonFatal(e) => logger.warn(s"$message", e) - } -} diff --git a/automation/src/test/scala/org/broadinstitute/dsde/workbench/util/LocalFileUtil.scala b/automation/src/test/scala/org/broadinstitute/dsde/workbench/util/LocalFileUtil.scala index 03c94ac6a02..814f6b9a90f 100644 --- a/automation/src/test/scala/org/broadinstitute/dsde/workbench/util/LocalFileUtil.scala +++ b/automation/src/test/scala/org/broadinstitute/dsde/workbench/util/LocalFileUtil.scala @@ -2,6 +2,7 @@ package org.broadinstitute.dsde.workbench.util import java.io.File import java.nio.file.Files +import org.broadinstitute.dsde.workbench.service.test.WebBrowserUtil import org.openqa.selenium.WebDriver diff --git a/automation/src/test/scala/org/broadinstitute/dsde/workbench/util/WebBrowserUtil.scala b/automation/src/test/scala/org/broadinstitute/dsde/workbench/util/WebBrowserUtil.scala deleted file mode 100644 index 7416bf702ee..00000000000 --- a/automation/src/test/scala/org/broadinstitute/dsde/workbench/util/WebBrowserUtil.scala +++ /dev/null @@ -1,257 +0,0 @@ -package org.broadinstitute.dsde.workbench.util - -import org.openqa.selenium.support.ui.{ExpectedCondition, WebDriverWait} -import org.openqa.selenium.{StaleElementReferenceException, WebDriver} -import org.scalatest.selenium.WebBrowser -import scala.collection.JavaConverters._ - -/** - * Mix-in utilities for ScalaTest's WebBrowser. - */ -trait WebBrowserUtil extends WebBrowser { - val defaultTimeOutInSeconds: Long = 30 - - /** - * Override of the base find() method to retry in the case of a - * StaleElementReferenceException. - */ - abstract override def find(query: Query)(implicit driver: WebDriver): Option[Element] = { - try { - super.find(query) - } catch { - case _: StaleElementReferenceException => this.find(query) - } - } - - abstract override def findAll(query: Query)(implicit driver: WebDriver): Iterator[Element] = { - try { - super.findAll(query) - } catch { - case _: StaleElementReferenceException => this.findAll(query) - } - } - - /** - * Extension to ScalaTest's Selenium DSL for waiting on changes in browser - * state. Example: - * - *
-    * await enabled id("myButton")
-    * 
- */ - object await { - - /** - * Waits for a condition to be met. - * - * @param condition function returning the Boolean result of the condition check - * @param timeOutInSeconds number of seconds to wait for the condition to be true - * @param webDriver implicit WebDriver for the WebDriverWait - */ - def condition(condition: => Boolean, timeOutInSeconds: Long = defaultTimeOutInSeconds)(implicit webDriver: WebDriver): Unit = { - withWaitForCondition(timeOutInSeconds) { - condition - } - } - - /** - * Waits for an element to be enabled. Returns the element found by the - * query to facilitate call chaining, e.g.: - * - * click on (await enabled id("my-button")) - * - * Returns null if the element is not found. Why null instead of None? It - * would be too easy for callers to map/flatmap an Option which is likely - * to delay failure of the test if it's None. For example, if trying to - * click on a button, nothing would happen instead of the test failing. - * The test would (hopefully) fail only when the next action it tries to - * do is not available. Understanding the cause of the failure would - * require more work, including probably looking at the failure - * screenshot. A NullPointerException when trying to interact with the - * element will result in a more immediate failure with a more obvious - * cause. - * - * @param query Query to locate the element - * @param timeOutInSeconds number of seconds to wait for the enabled element - * @param webDriver implicit WebDriver for the WebDriverWait - * @return the found element - */ - def enabled(query: Query, timeOutInSeconds: Long = defaultTimeOutInSeconds) - (implicit webDriver: WebDriver): Element = { - withWaitForElement(timeOutInSeconds) { - find(query).filter(_.isEnabled).orNull - } - } - - def writable(query: Query, timeoutInSeconds: Long = defaultTimeOutInSeconds) - (implicit webDriver: WebDriver): Element = { - withWaitForElement(timeoutInSeconds) { - findAll(query).find(_.attribute("readonly").isEmpty).orNull - } - } - - def notVisible(query: Query, timeOutInSeconds: Long = defaultTimeOutInSeconds) - (implicit webDriver: WebDriver): Unit = { - withWaitForCondition(timeOutInSeconds) { - !findAll(query).exists(_.isDisplayed) - } - } - - def forState(element: Element, state: String, timeOutInSeconds: Long = defaultTimeOutInSeconds) - (implicit webDriver: WebDriver): Element = { - withWaitForCondition(timeOutInSeconds) { - element.attribute("data-test-state").getOrElse("") == state - } - element - } - - def spinner(text: String, timeOutInSeconds: Long = defaultTimeOutInSeconds) - (implicit webDriver: WebDriver): Unit = { - // Micro-sleep to make sure the spinner has had a chance to appear before waiting for it to disappear. - Thread sleep 100 - notVisible(xpath(s"//*[@data-test-id='spinner-text' and contains(text(),'$text')]")) - } - - /** - * Waits for an element to be enabled, then clicks it. - * - * @param query Query to locate the element - * @param timeOutInSeconds number of seconds to wait for the enabled element - * @param webDriver implicit WebDriver for the WebDriverWait - */ - def thenClick(query: Query, timeOutInSeconds: Long = defaultTimeOutInSeconds)(implicit webDriver: WebDriver): Unit = { - val element = await enabled query - click on element - } - - /** - * Waits for an element containing the given text. - * TODO: this is currently untested - * - * @param text the text to search for - * @param timeOutInSeconds number of seconds to wait for the text - * @param webDriver implicit WebDriver for the WebDriverWait - */ - def text(text: String, timeOutInSeconds: Long = defaultTimeOutInSeconds)(implicit webDriver: WebDriver): Unit = { - await condition (find(withText(text)).isDefined, timeOutInSeconds) - } - - def visible(query: Query, timeOutInSeconds: Long = defaultTimeOutInSeconds) - (implicit webDriver: WebDriver): Unit = { - withWaitForCondition(timeOutInSeconds) { - find(query).exists(_.isDisplayed) - } - } - - private def withWaitForCondition(timeOutInSeconds: Long)(f: => Boolean)(implicit webDriver: WebDriver): Boolean = { - val wait = new WebDriverWait(webDriver, timeOutInSeconds) - wait until new java.util.function.Function[WebDriver, Boolean] { - override def apply(d: WebDriver): Boolean = { - try { - f - } catch { - case _: StaleElementReferenceException => false - } - } - } - } - - private def withWaitForElement(timeOutInSeconds: Long)(f: => Element)(implicit webDriver: WebDriver): Element = { - val wait = new WebDriverWait(webDriver, timeOutInSeconds) - wait until new java.util.function.Function[WebDriver, Element] { - override def apply(d: WebDriver): Element = { - try { - f - } catch { - case _: StaleElementReferenceException => null - } - } - } - } - } - - def enabled(q: Query)(implicit webDriver: WebDriver): Boolean = { - find(q).exists(_.isEnabled) - } - - /** - * Extension to ScalaTest's Selenium DSL for working with option elements. - */ - object option { - - /** - * Determines the value of an option based on its text. Example: - * - *
-      * singleSel("choices").value = option value "Choice 1"
-      * 
- * - * @param text text label of the option - * @param webDriver implicit WebDriver for the WebDriverWait - * @return the value of the option - */ - def value(text: String)(implicit webDriver: WebDriver): String = { - find(xpath(s"//option[text()='$text']")).get.underlying.getAttribute("value") - } - } - - /** - * Creates a Query for an element with a data-test-id attribute. - * - * @param id the expected data-test-id - * @param webDriver implicit WebDriver for the WebDriverWait - * @return a Query for the data-test-id - */ - def testId(id: String)(implicit webDriver: WebDriver): CssSelectorQuery = { - cssSelector(s"[data-test-id='$id']") - } - - def testState(state: String)(implicit webDriver: WebDriver): CssSelectorQuery = { - cssSelector(s"[data-test-state='$state']") - } - - def typeSelector(selector: String)(implicit webDriver: WebDriver): CssSelectorQuery = { - cssSelector(s"[type='$selector']") - } - - implicit class RichCssSelectorQuery(child: CssSelectorQuery) { - def inside(parent: CssSelectorQuery): CssSelectorQuery = { - CssSelectorQuery(parent.queryString + " " + child.queryString) - } - } - - def withText(text: String)(implicit webDriver: WebDriver): Query = { - xpath(s"//*[contains(text(),'$text')]") - } - - /** - * Creates a query for an element containing the given text. - * TODO: this is currently untested - * - * @param text the text to search for - * @param webDriver implicit WebDriver for the WebDriverWait - * @return a Query for the text - */ - def text(text: String)(implicit webDriver: WebDriver): Query = { - xpath(s"//*[contains(text(),'$text')]") - } - - /** - * Creates a Query for an element with a title attribute. - * - * @param title the expected title - * @param webDriver implicit WebDriver for the WebDriverWait - * @return a Query for the title - */ - def title(title: String)(implicit webDriver: WebDriver): Query = { - cssSelector(s"[title='$title']") - } - - def switchToNewTab(codeToOpenNewTab: => Unit)(implicit webDriver: WebDriver): Unit = { - val curTabs = webDriver.getWindowHandles.asScala - codeToOpenNewTab - val newTabs = webDriver.getWindowHandles.asScala - newTabs --= curTabs - switch to window(newTabs.head) - } -} diff --git a/docker/build.sh b/docker/build.sh index 968687c6df5..c3344570383 100755 --- a/docker/build.sh +++ b/docker/build.sh @@ -37,20 +37,31 @@ function make_jar() function docker_cmd() { if [ $DOCKER_CMD = "build" ] || [ $DOCKER_CMD = "push" ]; then - echo "building leonardo docker image..." - GIT_SHA=$(git rev-parse ${GIT_BRANCH}) - echo GIT_SHA=$GIT_SHA > env.properties # for jenkins jobs - docker build -t $REPO:${GIT_SHA:0:12} . + echo "building $PROJECT docker image..." + if [ "$ENV" != "dev" ] && [ "$ENV" != "alpha" ] && [ "$ENV" != "staging" ] && [ "$ENV" != "perf" ]; then + DOCKER_TAG=${BRANCH} + else + GIT_SHA=$(git rev-parse origin/${BRANCH}) + echo GIT_SHA=$GIT_SHA > env.properties + DOCKER_TAG=${GIT_SHA:0:12} + fi # builds the juptyer notebooks docker image that goes on dataproc clusters - bash ./jupyter-docker/build.sh build ${GIT_SHA:0:12} + bash ./jupyter-docker/build.sh build ${DOCKER_TAG} - if [ $DOCKER_CMD = "push" ]; then - echo "pushing leonardo docker image..." - docker push $REPO:${GIT_SHA:0:12} + echo "building $PROJECT-tests docker image..." + docker build -t $REPO:${DOCKER_TAG} . + cd automation + docker build -f Dockerfile-tests -t $TESTS_REPO:${DOCKER_TAG} . + cd .. + if [ $DOCKER_CMD = "push" ]; then + echo "pushing $PROJECT docker image..." + docker push $REPO:${DOCKER_TAG} + echo "pushing $PROJECT-tests docker image..." + docker push $TESTS_REPO:${DOCKER_TAG} # pushes the juptyer notebooks docker image that goes on dataproc clusters - bash ./jupyter-docker/build.sh push ${GIT_SHA:0:12} + bash ./jupyter-docker/build.sh push ${DOCKER_TAG} fi else echo "Not a valid docker option! Choose either build or push (which includes build)" @@ -59,8 +70,10 @@ function docker_cmd() # parse command line options DOCKER_CMD= -GIT_BRANCH=${GIT_BRANCH:-$(git rev-parse --abbrev-ref HEAD)} # default to current branch -REPO=${REPO:-broadinstitute/$PROJECT} # default to leonardo docker repo +BRANCH=${BRANCH:-$(git rev-parse --abbrev-ref HEAD)} # default to current branch +REPO=${REPO:-broadinstitute/$PROJECT} +TESTS_REPO=$REPO-tests +ENV=${ENV:-""} # if env is not set, push an image with branch name if [ -z "$1" ]; then echo "No argument supplied! Available choices are jar to build the jar and -d followed by a docker option (build or push)"