From 91f05741ea7be1fee50fa78d0821530b1d4cca5d Mon Sep 17 00:00:00 2001 From: Sam Schumacher <42777208+sam-schu@users.noreply.github.com> Date: Tue, 26 Nov 2024 14:53:45 -0500 Subject: [PATCH] [AN-225] Cromwell Google Batch API workspace setting (#3136) --- core/src/main/resources/swagger/api-docs.yaml | 14 +- .../slick/WorkspaceSettingComponent.scala | 10 +- .../workspace/WorkspaceSettingService.scala | 9 +- .../WorkspaceSettingRepositorySpec.scala | 47 ++- .../WorkspaceSettingServiceUnitTests.scala | 7 +- .../dsde/rawls/model/WorkspaceModel.scala | 19 +- .../dsde/rawls/model/WorkspaceModelSpec.scala | 276 +++++++++++++++--- 7 files changed, 326 insertions(+), 56 deletions(-) diff --git a/core/src/main/resources/swagger/api-docs.yaml b/core/src/main/resources/swagger/api-docs.yaml index a69ae4774b..61589bf712 100644 --- a/core/src/main/resources/swagger/api-docs.yaml +++ b/core/src/main/resources/swagger/api-docs.yaml @@ -5989,13 +5989,15 @@ components: - GcpBucketSoftDelete - GcpBucketRequesterPays - SeparateSubmissionFinalOutputs + - UseCromwellGcpBatchBackend config: description: The configuration of the workspace setting oneOf: - $ref: '#/components/schemas/WorkspaceSettingGcpBucketLifecycleConfig' - $ref: '#/components/schemas/WorkspaceSettingGcpBucketSoftDeleteConfig' - $ref: '#/components/schemas/WorkspaceSettingGcpBucketRequesterPaysConfig' - - $ref: '#/components/schemas/WorkspaceSettingSeparateSubmissionFinalOutputs' + - $ref: '#/components/schemas/WorkspaceSettingSeparateSubmissionFinalOutputsConfig' + - $ref: '#/components/schemas/WorkspaceSettingUseCromwellGcpBatchBackendConfig' WorkspaceSettingGcpBucketLifecycleConfig: required: - rules @@ -6054,7 +6056,7 @@ components: enabled: type: boolean description: Enabled status to set for requester pays - WorkspaceSettingSeparateSubmissionFinalOutputs: + WorkspaceSettingSeparateSubmissionFinalOutputsConfig: required: - enabled type: object @@ -6062,6 +6064,14 @@ components: enabled: type: boolean description: Whether submission final outputs should be separated from intermediate outputs + WorkspaceSettingUseCromwellGcpBatchBackendConfig: + required: + - enabled + type: object + properties: + enabled: + type: boolean + description: Whether workflows submitted to Cromwell should be run using Cromwell's GCP Batch backend WorkspaceSubmissionStats: required: - runningSubmissionsCount diff --git a/core/src/main/scala/org/broadinstitute/dsde/rawls/dataaccess/slick/WorkspaceSettingComponent.scala b/core/src/main/scala/org/broadinstitute/dsde/rawls/dataaccess/slick/WorkspaceSettingComponent.scala index 245e342192..009360fad2 100644 --- a/core/src/main/scala/org/broadinstitute/dsde/rawls/dataaccess/slick/WorkspaceSettingComponent.scala +++ b/core/src/main/scala/org/broadinstitute/dsde/rawls/dataaccess/slick/WorkspaceSettingComponent.scala @@ -4,13 +4,15 @@ import org.broadinstitute.dsde.rawls.model.WorkspaceJsonSupport.{ GcpBucketLifecycleConfigFormat, GcpBucketRequesterPaysConfigFormat, GcpBucketSoftDeleteConfigFormat, - SeparateSubmissionFinalOutputsConfigFormat + SeparateSubmissionFinalOutputsConfigFormat, + UseCromwellGcpBatchBackendConfigFormat } import org.broadinstitute.dsde.rawls.model.WorkspaceSettingConfig.{ GcpBucketLifecycleConfig, GcpBucketRequesterPaysConfig, GcpBucketSoftDeleteConfig, - SeparateSubmissionFinalOutputsConfig + SeparateSubmissionFinalOutputsConfig, + UseCromwellGcpBatchBackendConfig } import org.broadinstitute.dsde.rawls.model.WorkspaceSettingTypes.WorkspaceSettingType import org.broadinstitute.dsde.rawls.model._ @@ -71,6 +73,10 @@ object WorkspaceSettingRecord { SeparateSubmissionFinalOutputsSetting( workspaceSettingRecord.config.parseJson.convertTo[SeparateSubmissionFinalOutputsConfig] ) + case WorkspaceSettingTypes.UseCromwellGcpBatchBackend => + UseCromwellGcpBatchBackendSetting( + workspaceSettingRecord.config.parseJson.convertTo[UseCromwellGcpBatchBackendConfig] + ) } } } diff --git a/core/src/main/scala/org/broadinstitute/dsde/rawls/workspace/WorkspaceSettingService.scala b/core/src/main/scala/org/broadinstitute/dsde/rawls/workspace/WorkspaceSettingService.scala index 79ab9be54f..1ce51f1082 100644 --- a/core/src/main/scala/org/broadinstitute/dsde/rawls/workspace/WorkspaceSettingService.scala +++ b/core/src/main/scala/org/broadinstitute/dsde/rawls/workspace/WorkspaceSettingService.scala @@ -16,6 +16,7 @@ import org.broadinstitute.dsde.rawls.model.{ RawlsRequestContext, SamWorkspaceActions, SeparateSubmissionFinalOutputsSetting, + UseCromwellGcpBatchBackendSetting, Workspace, WorkspaceName, WorkspaceSetting, @@ -94,6 +95,7 @@ class WorkspaceSettingService(protected val ctx: RawlsRequestContext, } case GcpBucketRequesterPaysSetting(GcpBucketRequesterPaysConfig(_)) => None case SeparateSubmissionFinalOutputsSetting(SeparateSubmissionFinalOutputsConfig(_)) => None + case UseCromwellGcpBatchBackendSetting(UseCromwellGcpBatchBackendConfig(_)) => None } } @@ -158,11 +160,14 @@ class WorkspaceSettingService(protected val ctx: RawlsRequestContext, case GcpBucketRequesterPaysSetting(GcpBucketRequesterPaysConfig(enabled)) => gcsDAO.setRequesterPays(workspace.bucketName, enabled, workspace.googleProjectId) + // SeparateSubmissionFinalOutputsSetting and UseCromwellGcpBatchBackendSetting are not bucket settings, + // so we do not need to apply anything here + case SeparateSubmissionFinalOutputsSetting(SeparateSubmissionFinalOutputsConfig(_)) => - // SeparateSubmissionFinalOutputsSetting is not a bucket setting, so we don't need to apply anything here Future.successful(()) - case _ => throw new RawlsException("unsupported workspace setting") + case UseCromwellGcpBatchBackendSetting(UseCromwellGcpBatchBackendConfig(_)) => + Future.successful(()) } validateSettings(workspaceSettings) diff --git a/core/src/test/scala/org/broadinstitute/dsde/rawls/workspace/WorkspaceSettingRepositorySpec.scala b/core/src/test/scala/org/broadinstitute/dsde/rawls/workspace/WorkspaceSettingRepositorySpec.scala index 84d75ba649..ed5e8deae3 100644 --- a/core/src/test/scala/org/broadinstitute/dsde/rawls/workspace/WorkspaceSettingRepositorySpec.scala +++ b/core/src/test/scala/org/broadinstitute/dsde/rawls/workspace/WorkspaceSettingRepositorySpec.scala @@ -9,15 +9,18 @@ import org.broadinstitute.dsde.rawls.model.WorkspaceSettingConfig.{ GcpBucketLifecycleConfig, GcpBucketLifecycleRule, GcpBucketRequesterPaysConfig, - GcpBucketSoftDeleteConfig + GcpBucketSoftDeleteConfig, + SeparateSubmissionFinalOutputsConfig, + UseCromwellGcpBatchBackendConfig } import org.broadinstitute.dsde.rawls.model.WorkspaceSettingTypes.GcpBucketSoftDelete import org.broadinstitute.dsde.rawls.model.{ GcpBucketLifecycleSetting, GcpBucketRequesterPaysSetting, GcpBucketSoftDeleteSetting, + SeparateSubmissionFinalOutputsSetting, + UseCromwellGcpBatchBackendSetting, Workspace, - WorkspaceSetting, WorkspaceSettingTypes } import org.joda.time.DateTime @@ -99,6 +102,46 @@ class WorkspaceSettingRepositorySpec assertResult(result)(List(appliedSetting)) } + // Helps ensure that WorkspaceSettingRecord.toWorkspaceSetting in WorkspaceSettingComponent.scala + // is able to successfully create every type of workspace setting from a corresponding record + for { + workspaceSetting <- List( + GcpBucketLifecycleSetting(GcpBucketLifecycleConfig(List())), + GcpBucketSoftDeleteSetting(GcpBucketSoftDeleteConfig(0)), + GcpBucketRequesterPaysSetting(GcpBucketRequesterPaysConfig(true)), + SeparateSubmissionFinalOutputsSetting(SeparateSubmissionFinalOutputsConfig(true)), + UseCromwellGcpBatchBackendSetting(UseCromwellGcpBatchBackendConfig(true)) + ) + } + it should s"be able to get a ${workspaceSetting.getClass.getSimpleName}" in { + val repo = new WorkspaceSettingRepository(slickDataSource) + val workspaceRepo = new WorkspaceRepository(slickDataSource) + val ws: Workspace = makeWorkspace() + Await.result(workspaceRepo.createWorkspace(ws), Duration.Inf) + + Await.result( + slickDataSource.inTransaction { dataAccess => + for { + _ <- dataAccess.workspaceSettingQuery.saveAll(ws.workspaceIdAsUUID, + List(workspaceSetting), + userInfo.userSubjectId + ) + _ <- dataAccess.workspaceSettingQuery.updateSettingStatus( + ws.workspaceIdAsUUID, + workspaceSetting.settingType, + WorkspaceSettingRecord.SettingStatus.Pending, + WorkspaceSettingRecord.SettingStatus.Applied + ) + } yield () + }, + Duration.Inf + ) + + val result = Await.result(repo.getWorkspaceSettings(ws.workspaceIdAsUUID), Duration.Inf) + + assertResult(result)(List(workspaceSetting)) + } + behavior of "getWorkspacesSettingsOfType" it should "return applied soft delete setting when soft delete type is requested" in { diff --git a/core/src/test/scala/org/broadinstitute/dsde/rawls/workspace/WorkspaceSettingServiceUnitTests.scala b/core/src/test/scala/org/broadinstitute/dsde/rawls/workspace/WorkspaceSettingServiceUnitTests.scala index 7df83943b2..da9dc0dccc 100644 --- a/core/src/test/scala/org/broadinstitute/dsde/rawls/workspace/WorkspaceSettingServiceUnitTests.scala +++ b/core/src/test/scala/org/broadinstitute/dsde/rawls/workspace/WorkspaceSettingServiceUnitTests.scala @@ -13,7 +13,8 @@ import org.broadinstitute.dsde.rawls.model.WorkspaceSettingConfig.{ GcpBucketLifecycleRule, GcpBucketRequesterPaysConfig, GcpBucketSoftDeleteConfig, - SeparateSubmissionFinalOutputsConfig + SeparateSubmissionFinalOutputsConfig, + UseCromwellGcpBatchBackendConfig } import org.broadinstitute.dsde.rawls.model.{ ErrorReport, @@ -27,6 +28,7 @@ import org.broadinstitute.dsde.rawls.model.{ SamUserStatusResponse, SamWorkspaceActions, SeparateSubmissionFinalOutputsSetting, + UseCromwellGcpBatchBackendSetting, UserInfo, Workspace, WorkspaceSettingTypes @@ -184,7 +186,8 @@ class WorkspaceSettingServiceUnitTests extends AnyFlatSpec with MockitoTestUtils GcpBucketLifecycleSetting(GcpBucketLifecycleConfig(List.empty)), GcpBucketSoftDeleteSetting(GcpBucketSoftDeleteConfig(7.days.toSeconds)), GcpBucketRequesterPaysSetting(GcpBucketRequesterPaysConfig(true)), - SeparateSubmissionFinalOutputsSetting(SeparateSubmissionFinalOutputsConfig(true)) + SeparateSubmissionFinalOutputsSetting(SeparateSubmissionFinalOutputsConfig(true)), + UseCromwellGcpBatchBackendSetting(UseCromwellGcpBatchBackendConfig(true)) ) val workspaceRepository = mock[WorkspaceRepository] diff --git a/model/src/main/scala/org/broadinstitute/dsde/rawls/model/WorkspaceModel.scala b/model/src/main/scala/org/broadinstitute/dsde/rawls/model/WorkspaceModel.scala index e7c9c115aa..e7b593b68a 100644 --- a/model/src/main/scala/org/broadinstitute/dsde/rawls/model/WorkspaceModel.scala +++ b/model/src/main/scala/org/broadinstitute/dsde/rawls/model/WorkspaceModel.scala @@ -18,13 +18,15 @@ import org.broadinstitute.dsde.rawls.model.WorkspaceSettingConfig.{ GcpBucketLifecycleRule, GcpBucketRequesterPaysConfig, GcpBucketSoftDeleteConfig, - SeparateSubmissionFinalOutputsConfig + SeparateSubmissionFinalOutputsConfig, + UseCromwellGcpBatchBackendConfig } import org.broadinstitute.dsde.rawls.model.WorkspaceSettingTypes.{ GcpBucketLifecycle, GcpBucketRequesterPays, GcpBucketSoftDelete, SeparateSubmissionFinalOutputs, + UseCromwellGcpBatchBackend, WorkspaceSettingType } import org.broadinstitute.dsde.rawls.model.WorkspaceState.WorkspaceState @@ -591,6 +593,9 @@ case class GcpBucketRequesterPaysSetting(override val config: GcpBucketRequester case class SeparateSubmissionFinalOutputsSetting(override val config: SeparateSubmissionFinalOutputsConfig) extends WorkspaceSetting(settingType = WorkspaceSettingTypes.SeparateSubmissionFinalOutputs, config) +case class UseCromwellGcpBatchBackendSetting(override val config: UseCromwellGcpBatchBackendConfig) + extends WorkspaceSetting(settingType = WorkspaceSettingTypes.UseCromwellGcpBatchBackend, config) + object WorkspaceSettingTypes { sealed trait WorkspaceSettingType extends RawlsEnumeration[WorkspaceSettingType] { override def toString: String = getClass.getSimpleName.stripSuffix("$") @@ -602,6 +607,7 @@ object WorkspaceSettingTypes { case "gcpbucketsoftdelete" => GcpBucketSoftDelete case "gcpbucketrequesterpays" => GcpBucketRequesterPays case "separatesubmissionfinaloutputs" => SeparateSubmissionFinalOutputs + case "usecromwellgcpbatchbackend" => UseCromwellGcpBatchBackend case _ => throw new RawlsException(s"invalid WorkspaceSetting [$name]") } @@ -612,6 +618,8 @@ object WorkspaceSettingTypes { case object GcpBucketRequesterPays extends WorkspaceSettingType case object SeparateSubmissionFinalOutputs extends WorkspaceSettingType + + case object UseCromwellGcpBatchBackend extends WorkspaceSettingType } sealed trait WorkspaceSettingConfig @@ -629,6 +637,8 @@ object WorkspaceSettingConfig { case class GcpBucketRequesterPaysConfig(enabled: Boolean) extends WorkspaceSettingConfig case class SeparateSubmissionFinalOutputsConfig(enabled: Boolean) extends WorkspaceSettingConfig + + case class UseCromwellGcpBatchBackendConfig(enabled: Boolean) extends WorkspaceSettingConfig } case class WorkspaceSettingResponse(successes: List[WorkspaceSetting], failures: Map[WorkspaceSettingType, ErrorReport]) @@ -1261,6 +1271,9 @@ class WorkspaceJsonSupport extends JsonSupport { jsonFormat1( SeparateSubmissionFinalOutputsConfig.apply ) + implicit val UseCromwellGcpBatchBackendConfigFormat: RootJsonFormat[UseCromwellGcpBatchBackendConfig] = jsonFormat1( + UseCromwellGcpBatchBackendConfig.apply + ) implicit object WorkspaceSettingTypeFormat extends RootJsonFormat[WorkspaceSettingType] { override def write(obj: WorkspaceSettingType): JsValue = JsString(obj.toString) @@ -1277,6 +1290,7 @@ class WorkspaceJsonSupport extends JsonSupport { case config: GcpBucketSoftDeleteConfig => config.toJson case config: GcpBucketRequesterPaysConfig => config.toJson case config: SeparateSubmissionFinalOutputsConfig => config.toJson + case config: UseCromwellGcpBatchBackendConfig => config.toJson } // We prevent reading WorkspaceSettingConfig directly because we need @@ -1302,7 +1316,8 @@ class WorkspaceJsonSupport extends JsonSupport { GcpBucketRequesterPaysSetting(fields("config").convertTo[GcpBucketRequesterPaysConfig]) case SeparateSubmissionFinalOutputs => SeparateSubmissionFinalOutputsSetting(fields("config").convertTo[SeparateSubmissionFinalOutputsConfig]) - case _ => throw DeserializationException(s"unexpected setting type $settingType") + case UseCromwellGcpBatchBackend => + UseCromwellGcpBatchBackendSetting(fields("config").convertTo[UseCromwellGcpBatchBackendConfig]) } } } diff --git a/model/src/test/scala/org/broadinstitute/dsde/rawls/model/WorkspaceModelSpec.scala b/model/src/test/scala/org/broadinstitute/dsde/rawls/model/WorkspaceModelSpec.scala index 5a2ff05fbc..91bc0e5137 100644 --- a/model/src/test/scala/org/broadinstitute/dsde/rawls/model/WorkspaceModelSpec.scala +++ b/model/src/test/scala/org/broadinstitute/dsde/rawls/model/WorkspaceModelSpec.scala @@ -11,7 +11,8 @@ import org.broadinstitute.dsde.rawls.model.WorkspaceSettingConfig.{ GcpBucketLifecycleRule, GcpBucketRequesterPaysConfig, GcpBucketSoftDeleteConfig, - SeparateSubmissionFinalOutputsConfig + SeparateSubmissionFinalOutputsConfig, + UseCromwellGcpBatchBackendConfig } import org.joda.time.DateTime import org.scalatest.freespec.AnyFreeSpec @@ -693,7 +694,73 @@ class WorkspaceModelSpec extends AnyFreeSpec with Matchers { } } + "Workspace Setting Type" - { + "should parse workspace setting type properly" in { + WorkspaceSettingTypes.withName("gcpbucketlifecycle") shouldBe WorkspaceSettingTypes.GcpBucketLifecycle + WorkspaceSettingTypes.withName("gcpbucketsoftdelete") shouldBe WorkspaceSettingTypes.GcpBucketSoftDelete + WorkspaceSettingTypes.withName("gcpbucketrequesterpays") shouldBe WorkspaceSettingTypes.GcpBucketRequesterPays + WorkspaceSettingTypes.withName( + "separatesubmissionfinaloutputs" + ) shouldBe WorkspaceSettingTypes.SeparateSubmissionFinalOutputs + WorkspaceSettingTypes.withName( + "usecromwellgcpbatchbackend" + ) shouldBe WorkspaceSettingTypes.UseCromwellGcpBatchBackend + } + + "should fail trying to parse an invalid workspace setting type" in { + val thrown = intercept[RawlsException] { + WorkspaceSettingTypes.withName("incorrect") + } + + thrown.getMessage.contains("invalid WorkspaceSetting [incorrect]") + } + + "should output the string representation" in { + WorkspaceSettingTypes.GcpBucketLifecycle.toString shouldBe "GcpBucketLifecycle" + WorkspaceSettingTypes.GcpBucketSoftDelete.toString shouldBe "GcpBucketSoftDelete" + WorkspaceSettingTypes.GcpBucketRequesterPays.toString shouldBe "GcpBucketRequesterPays" + WorkspaceSettingTypes.SeparateSubmissionFinalOutputs.toString shouldBe "SeparateSubmissionFinalOutputs" + WorkspaceSettingTypes.UseCromwellGcpBatchBackend.toString shouldBe "UseCromwellGcpBatchBackend" + } + } + "GoogleBucketLifecycleSettings" - { + "serializes properly" in { + val lifecycleSettingJson = + """{ + | "settingType": "GcpBucketLifecycle", + | "config": { + | "rules": [ + | { + | "action": { + | "actionType": "Delete" + | }, + | "conditions": { + | "age": 30, + | "matchesPrefix": [ + | "prefix1", + | "prefix2" + | ] + | } + | } + | ] + | } + | }""".stripMargin.parseJson + assertResult(lifecycleSettingJson) { + WorkspaceSettingFormat.write( + GcpBucketLifecycleSetting( + GcpBucketLifecycleConfig( + List( + GcpBucketLifecycleRule(GcpBucketLifecycleAction("Delete"), + GcpBucketLifecycleCondition(Some(Set("prefix1", "prefix2")), Some(30)) + ) + ) + ) + ) + ) + } + } + "parses lifecycle settings with matchesPrefix and age" in { val lifecycleSetting = """{ @@ -891,6 +958,23 @@ class WorkspaceModelSpec extends AnyFreeSpec with Matchers { } "GoogleBucketSoftDeleteSetting" - { + "serializes properly" in { + val softDeleteSettingJson = + """{ + | "settingType": "GcpBucketSoftDelete", + | "config": { + | "retentionDurationInSeconds": 500 + | } + | }""".stripMargin.parseJson + assertResult(softDeleteSettingJson) { + WorkspaceSettingFormat.write( + GcpBucketSoftDeleteSetting( + GcpBucketSoftDeleteConfig(500) + ) + ) + } + } + "parses soft delete setting with retentionDurationInSeconds" in { val softDeleteSetting = """{ @@ -957,6 +1041,23 @@ class WorkspaceModelSpec extends AnyFreeSpec with Matchers { } "GoogleBucketRequesterPaysSettings" - { + "serializes properly" in { + val requesterPaysSettingJson = + """{ + | "settingType": "GcpBucketRequesterPays", + | "config": { + | "enabled": true + | } + | }""".stripMargin.parseJson + assertResult(requesterPaysSettingJson) { + WorkspaceSettingFormat.write( + GcpBucketRequesterPaysSetting( + GcpBucketRequesterPaysConfig(true) + ) + ) + } + } + "parses requester pays setting with enabled" in { val requesterPaysSetting = """{ @@ -1008,57 +1109,144 @@ class WorkspaceModelSpec extends AnyFreeSpec with Matchers { } } } - } - "SeparateSubmissionFinalOutputsSetting" - { - "parses setting with enabled" in { - val setting = - """{ - | "settingType": "SeparateSubmissionFinalOutputs", - | "config": { - | "enabled": true - | } - | }""".stripMargin.parseJson - assertResult { - SeparateSubmissionFinalOutputsSetting( - SeparateSubmissionFinalOutputsConfig(true) - ) - } { - WorkspaceSettingFormat.read(setting) + "SeparateSubmissionFinalOutputsSetting" - { + "serializes properly" in { + val settingJson = + """{ + | "settingType": "SeparateSubmissionFinalOutputs", + | "config": { + | "enabled": true + | } + | }""".stripMargin.parseJson + assertResult(settingJson) { + WorkspaceSettingFormat.write( + SeparateSubmissionFinalOutputsSetting( + SeparateSubmissionFinalOutputsConfig(true) + ) + ) + } } - } - "throws an exception for missing enabled" in { - val settingNoEnabled = - """{ - | "settingType": "SeparateSubmissionFinalOutputs", - | "config": {} - | }""".stripMargin.parseJson - intercept[DeserializationException] { - WorkspaceSettingFormat.read(settingNoEnabled) + "parses setting with enabled" in { + val setting = + """{ + | "settingType": "SeparateSubmissionFinalOutputs", + | "config": { + | "enabled": true + | } + | }""".stripMargin.parseJson + assertResult { + SeparateSubmissionFinalOutputsSetting( + SeparateSubmissionFinalOutputsConfig(true) + ) + } { + WorkspaceSettingFormat.read(setting) + } } - } - "throws an exception for missing config" in { - val settingNoConfig = - """{ - | "settingType": "SeparateSubmissionFinalOutputs" - | }""".stripMargin.parseJson - intercept[NoSuchElementException] { - WorkspaceSettingFormat.read(settingNoConfig) + "throws an exception for missing enabled" in { + val settingNoEnabled = + """{ + | "settingType": "SeparateSubmissionFinalOutputs", + | "config": {} + | }""".stripMargin.parseJson + intercept[DeserializationException] { + WorkspaceSettingFormat.read(settingNoEnabled) + } + } + + "throws an exception for missing config" in { + val settingNoConfig = + """{ + | "settingType": "SeparateSubmissionFinalOutputs" + | }""".stripMargin.parseJson + intercept[NoSuchElementException] { + WorkspaceSettingFormat.read(settingNoConfig) + } + } + + "throws an exception for incorrect format" in { + val settingBadConfig = + """{ + | "settingType": "SeparateSubmissionFinalOutputs", + | "config": { + | "enabled": 0 + | } + | }""".stripMargin.parseJson + intercept[DeserializationException] { + WorkspaceSettingFormat.read(settingBadConfig) + } } } - "throws an exception for incorrect format" in { - val settingBadConfig = - """{ - | "settingType": "SeparateSubmissionFinalOutputs", - | "config": { - | "enabled": 0 - | } - | }""".stripMargin.parseJson - intercept[DeserializationException] { - WorkspaceSettingFormat.read(settingBadConfig) + "UseCromwellGcpBatchBackendSetting" - { + "serializes properly" in { + val settingJson = + """{ + | "settingType": "UseCromwellGcpBatchBackend", + | "config": { + | "enabled": true + | } + | }""".stripMargin.parseJson + assertResult(settingJson) { + WorkspaceSettingFormat.write( + UseCromwellGcpBatchBackendSetting( + UseCromwellGcpBatchBackendConfig(true) + ) + ) + } + } + + "parses setting with enabled" in { + val setting = + """{ + | "settingType": "UseCromwellGcpBatchBackend", + | "config": { + | "enabled": true + | } + | }""".stripMargin.parseJson + assertResult { + UseCromwellGcpBatchBackendSetting( + UseCromwellGcpBatchBackendConfig(true) + ) + } { + WorkspaceSettingFormat.read(setting) + } + } + + "throws an exception for missing enabled" in { + val settingNoEnabled = + """{ + | "settingType": "UseCromwellGcpBatchBackend", + | "config": {} + | }""".stripMargin.parseJson + intercept[DeserializationException] { + WorkspaceSettingFormat.read(settingNoEnabled) + } + } + + "throws an exception for missing config" in { + val settingNoConfig = + """{ + | "settingType": "UseCromwellGcpBatchBackend" + | }""".stripMargin.parseJson + intercept[NoSuchElementException] { + WorkspaceSettingFormat.read(settingNoConfig) + } + } + + "throws an exception for incorrect format" in { + val settingBadConfig = + """{ + | "settingType": "UseCromwellGcpBatchBackend", + | "config": { + | "enabled": 0 + | } + | }""".stripMargin.parseJson + intercept[DeserializationException] { + WorkspaceSettingFormat.read(settingBadConfig) + } } } }