Skip to content

Commit

Permalink
ledger-api-client: Add test cases for LedgerClient. (digital-asset#…
Browse files Browse the repository at this point in the history
…7195)

* ledger-api-client: Add integration tests for the simple stuff.

* sandbox-common: Make `SandboxFixtureWithAuth` a mixin.

This makes it useful with `SandboxNextFixture` as well as
`SandboxFixture`.

Also, add types to non-private fields and methods, and make more fields
protected rather than public.

* ledger-api-client: Add tests to make sure the token is passed through.

CHANGELOG_BEGIN
CHANGELOG_END

* sandbox-common: Tokens are for auth, not auth.
  • Loading branch information
SamirTalwar authored Aug 20, 2020
1 parent ba74146 commit 30564a7
Show file tree
Hide file tree
Showing 13 changed files with 272 additions and 115 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import java.nio.file.Files
import java.time.Duration
import java.util.concurrent.atomic.AtomicReference

import com.daml.lf.data.Ref.Party
import com.daml.extractor.config.{ExtractorConfig, SnapshotEndSetting}
import com.daml.extractor.ledger.types.TransactionTree
import com.daml.extractor.targets.TextPrintTarget
Expand All @@ -20,7 +19,9 @@ import com.daml.ledger.api.v1.command_service.{CommandServiceGrpc, SubmitAndWait
import com.daml.ledger.api.v1.ledger_offset.LedgerOffset
import com.daml.ledger.client.services.commands.SynchronousCommandClient
import com.daml.ledger.service.LedgerReader.PackageStore
import com.daml.platform.sandbox.services.{SandboxFixtureWithAuth, TestCommands}
import com.daml.lf.data.Ref.Party
import com.daml.platform.sandbox.SandboxRequiringAuthorization
import com.daml.platform.sandbox.services.{SandboxFixture, TestCommands}
import com.daml.timer.Delayed
import org.scalatest.{AsyncFlatSpec, Matchers}
import org.slf4j.LoggerFactory
Expand All @@ -34,7 +35,8 @@ import scala.util.{Failure, Success}

final class AuthSpec
extends AsyncFlatSpec
with SandboxFixtureWithAuth
with SandboxFixture
with SandboxRequiringAuthorization
with SuiteResourceManagementAroundAll
with Matchers
with TestCommands {
Expand Down
1 change: 1 addition & 0 deletions language-support/scala/codegen-sample-app/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ da_scala_test(
"//ledger-api/rs-grpc-bridge",
"//ledger-api/testing-utils",
"//ledger/caching",
"//ledger/ledger-api-auth",
"//ledger/ledger-api-client",
"//ledger/ledger-api-common",
"//ledger/participant-integration-api",
Expand Down
2 changes: 2 additions & 0 deletions ledger/ledger-api-client/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ da_scala_test_suite(
"//ledger-api/rs-grpc-bridge",
"//ledger-api/testing-utils",
"//ledger/caching",
"//ledger/ledger-api-auth",
"//ledger/ledger-api-common",
"//ledger/ledger-api-domain",
"//ledger/participant-integration-api",
Expand All @@ -83,6 +84,7 @@ da_scala_test_suite(
"//ledger/sandbox-common:sandbox-common-scala-tests-lib",
"//ledger/test-common",
"//libs-scala/direct-execution-context",
"//libs-scala/grpc-utils",
"//libs-scala/ports",
"//libs-scala/resources",
"@maven//:ch_qos_logback_logback_classic",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

package com.daml.ledger.client

import com.daml.grpc.GrpcException
import com.daml.ledger.api.domain
import com.daml.ledger.api.testing.utils.{AkkaBeforeAndAfterAll, SuiteResourceManagementAroundEach}
import com.daml.ledger.client.configuration.{
CommandClientConfiguration,
LedgerClientConfiguration,
LedgerIdRequirement
}
import com.daml.platform.common.LedgerIdMode
import com.daml.platform.sandbox.SandboxRequiringAuthorization
import com.daml.platform.sandbox.config.SandboxConfig
import com.daml.platform.sandboxnext.SandboxNextFixture
import org.scalatest.{AsyncWordSpec, Inside, Matchers}

final class LedgerClientAuthIT
extends AsyncWordSpec
with Matchers
with Inside
with AkkaBeforeAndAfterAll
with SuiteResourceManagementAroundEach
with SandboxNextFixture
with SandboxRequiringAuthorization {

private val LedgerId =
domain.LedgerId(s"${classOf[LedgerClientAuthIT].getSimpleName.toLowerCase}-ledger-id")

private val ClientConfigurationWithoutToken = LedgerClientConfiguration(
applicationId = classOf[LedgerClientAuthIT].getSimpleName,
ledgerIdRequirement = LedgerIdRequirement.none,
commandClient = CommandClientConfiguration.default,
sslContext = None,
token = None,
)

private val ClientConfiguration = ClientConfigurationWithoutToken.copy(
token = Some(toHeader(readOnlyToken("Read-only party"))),
)

override protected def config: SandboxConfig = super.config.copy(
ledgerIdMode = LedgerIdMode.Static(LedgerId),
)

"the ledger client" when {
"it has a read-only token" should {
"retrieve the ledger ID" in {
for {
client <- LedgerClient(channel, ClientConfiguration)
} yield {
client.ledgerId should be(LedgerId)
}
}

"fail to conduct an admin operation with the same token" in {
for {
client <- LedgerClient(channel, ClientConfiguration)
exception <- client.partyManagementClient
.allocateParty(hint = Some("Bob"), displayName = None)
.failed
} yield {
inside(exception) {
case GrpcException.PERMISSION_DENIED() => succeed
}
}
}

"succeed in conducting an admin operation with an admin token" in {
val partyName = "Carol"
for {
client <- LedgerClient(channel, ClientConfiguration)
allocatedParty <- client.partyManagementClient
.allocateParty(
hint = Some(partyName),
displayName = Some(partyName),
token = Some(toHeader(adminToken)),
)
} yield {
allocatedParty.displayName should be(Some(partyName))
}
}
}

"it does not have a token" should {
"fail to construct" in {
for {
exception <- LedgerClient(channel, ClientConfigurationWithoutToken).failed
} yield {
inside(exception) {
case GrpcException.UNAUTHENTICATED() => succeed
}
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,20 @@

package com.daml.ledger.client

import com.daml.ledger.api.domain
import com.daml.ledger.api.testing.utils.{AkkaBeforeAndAfterAll, SuiteResourceManagementAroundEach}
import com.daml.ledger.client.configuration.{
CommandClientConfiguration,
LedgerClientConfiguration,
LedgerIdRequirement
}
import com.daml.lf.data.Ref
import com.daml.platform.common.LedgerIdMode
import com.daml.platform.sandbox.config.SandboxConfig
import com.daml.platform.sandboxnext.SandboxNextFixture
import io.grpc.ManagedChannel
import org.scalatest.{AsyncWordSpec, Inside, Matchers}
import scalaz.OneAnd

final class LedgerClientIT
extends AsyncWordSpec
Expand All @@ -20,18 +25,48 @@ final class LedgerClientIT
with AkkaBeforeAndAfterAll
with SuiteResourceManagementAroundEach
with SandboxNextFixture {

private val LedgerId =
domain.LedgerId(s"${classOf[LedgerClientIT].getSimpleName.toLowerCase}-ledger-id")

private val ClientConfiguration = LedgerClientConfiguration(
applicationId = classOf[LedgerClientIT].getSimpleName,
ledgerIdRequirement = LedgerIdRequirement.none,
commandClient = CommandClientConfiguration.default,
sslContext = None,
token = None,
)

override protected def config: SandboxConfig = super.config.copy(
ledgerIdMode = LedgerIdMode.Static(LedgerId),
)

"the ledger client" should {
"shut down the channel when closed" in {
val clientConfig = LedgerClientConfiguration(
applicationId = classOf[LedgerClientIT].getSimpleName,
ledgerIdRequirement = LedgerIdRequirement.none,
commandClient = CommandClientConfiguration.default,
sslContext = None,
token = None,
)
"retrieve the ledger ID" in {
for {
client <- LedgerClient(channel, ClientConfiguration)
} yield {
client.ledgerId should be(LedgerId)
}
}

"make some requests" in {
val partyName = "Alice"
for {
client <- LedgerClient(channel, ClientConfiguration)
// The request type is irrelevant here; the point is that we can make some.
allocatedParty <- client.partyManagementClient
.allocateParty(hint = Some(partyName), displayName = None)
retrievedParties <- client.partyManagementClient
.getParties(OneAnd(Ref.Party.assertFromString(partyName), Set.empty))
} yield {
retrievedParties should be(List(allocatedParty))
}
}

"shut down the channel when closed" in {
for {
client <- LedgerClient(channel, clientConfig)
client <- LedgerClient(channel, ClientConfiguration)
} yield {
inside(channel) {
case channel: ManagedChannel =>
Expand Down
3 changes: 0 additions & 3 deletions ledger/sandbox-classic/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,6 @@ da_scala_library(
"//language-support/scala/bindings",
"//ledger-api/rs-grpc-bridge",
"//ledger-api/testing-utils",
"//ledger-service/jwt",
"//ledger/caching",
"//ledger/ledger-api-auth",
"//ledger/ledger-api-auth-client",
Expand All @@ -163,12 +162,10 @@ da_scala_library(
"//libs-scala/resources",
"//libs-scala/timer-utils",
"@maven//:ch_qos_logback_logback_classic",
"@maven//:com_auth0_java_jwt",
"@maven//:com_typesafe_akka_akka_actor_2_12",
"@maven//:com_typesafe_akka_akka_stream_2_12",
"@maven//:com_typesafe_play_anorm_2_12",
"@maven//:com_typesafe_play_anorm_tokenizer_2_12",
"@maven//:com_typesafe_scala_logging_scala_logging_2_12",
"@maven//:io_dropwizard_metrics_metrics_core",
"@maven//:org_scalactic_scalactic_2_12",
"@maven//:org_scalatest_scalatest_2_12",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import com.daml.ledger.api.auth.client.LedgerCallCredentials
import com.daml.ledger.api.testing.utils.SuiteResourceManagementAroundAll
import com.daml.ledger.api.v1.ledger_offset.LedgerOffset
import com.daml.ledger.api.v1.transaction_filter.{Filters, TransactionFilter}
import com.daml.platform.sandbox.services.SandboxFixtureWithAuth
import com.daml.platform.sandbox.SandboxRequiringAuthorization
import com.daml.platform.sandbox.services.SandboxFixture
import io.grpc.Status
import io.grpc.stub.AbstractStub
import org.scalatest.{Assertion, AsyncFlatSpec, Matchers}
Expand All @@ -21,7 +22,8 @@ import scala.util.control.NonFatal

trait ServiceCallAuthTests
extends AsyncFlatSpec
with SandboxFixtureWithAuth
with SandboxFixture
with SandboxRequiringAuthorization
with SuiteResourceManagementAroundAll
with Matchers {

Expand All @@ -46,7 +48,8 @@ trait ServiceCallAuthTests
case NonFatal(e) => fail(e)
}

protected def txFilterFor(party: String) = Some(TransactionFilter(Map(party -> Filters())))
protected def txFilterFor(party: String): Option[TransactionFilter] =
Some(TransactionFilter(Map(party -> Filters())))

protected def ledgerBegin: LedgerOffset =
LedgerOffset(LedgerOffset.Value.Boundary(LedgerOffset.LedgerBoundary.LEDGER_BEGIN))
Expand All @@ -57,46 +60,47 @@ trait ServiceCallAuthTests
expectUnauthenticated(serviceCallWithToken(None))
}

protected val canActAsRandomParty =
protected val canActAsRandomParty: Option[String] =
Option(toHeader(readWriteToken(UUID.randomUUID.toString)))
protected val canActAsRandomPartyExpired =
protected val canActAsRandomPartyExpired: Option[String] =
Option(toHeader(expiringIn(Duration.ofDays(-1), readWriteToken(UUID.randomUUID.toString))))
protected val canActAsRandomPartyExpiresTomorrow =
protected val canActAsRandomPartyExpiresTomorrow: Option[String] =
Option(toHeader(expiringIn(Duration.ofDays(1), readWriteToken(UUID.randomUUID.toString))))

protected val canReadAsRandomParty =
protected val canReadAsRandomParty: Option[String] =
Option(toHeader(readOnlyToken(UUID.randomUUID.toString)))
protected val canReadAsRandomPartyExpired =
protected val canReadAsRandomPartyExpired: Option[String] =
Option(toHeader(expiringIn(Duration.ofDays(-1), readOnlyToken(UUID.randomUUID.toString))))
protected val canReadAsRandomPartyExpiresTomorrow =
protected val canReadAsRandomPartyExpiresTomorrow: Option[String] =
Option(toHeader(expiringIn(Duration.ofDays(1), readOnlyToken(UUID.randomUUID.toString))))

protected val canReadAsAdmin =
protected val canReadAsAdmin: Option[String] =
Option(toHeader(adminToken))
protected val canReadAsAdminExpired =
protected val canReadAsAdminExpired: Option[String] =
Option(toHeader(expiringIn(Duration.ofDays(-1), adminToken)))
protected val canReadAsAdminExpiresTomorrow = Option(
toHeader(expiringIn(Duration.ofDays(1), adminToken)))
protected val canReadAsAdminExpiresTomorrow: Option[String] =
Option(toHeader(expiringIn(Duration.ofDays(1), adminToken)))

// Note: lazy val, because the ledger ID is only known after the sandbox start
protected lazy val canReadAsRandomPartyActualLedgerId =
protected lazy val canReadAsRandomPartyActualLedgerId: Option[String] =
Option(toHeader(forLedgerId(unwrappedLedgerId, readOnlyToken(UUID.randomUUID.toString))))
protected val canReadAsRandomPartyRandomLedgerId =
protected val canReadAsRandomPartyRandomLedgerId: Option[String] =
Option(toHeader(forLedgerId(UUID.randomUUID.toString, readOnlyToken(UUID.randomUUID.toString))))
protected val canReadAsRandomPartyActualParticipantId =
protected val canReadAsRandomPartyActualParticipantId: Option[String] =
Option(
toHeader(forParticipantId("sandbox-participant", readOnlyToken(UUID.randomUUID.toString))))
protected val canReadAsRandomPartyRandomParticipantId =
protected val canReadAsRandomPartyRandomParticipantId: Option[String] =
Option(
toHeader(forParticipantId(UUID.randomUUID.toString, readOnlyToken(UUID.randomUUID.toString))))

// Note: lazy val, because the ledger ID is only known after the sandbox start
protected lazy val canReadAsAdminActualLedgerId =
protected lazy val canReadAsAdminActualLedgerId: Option[String] =
Option(toHeader(forLedgerId(unwrappedLedgerId, adminToken)))
protected val canReadAsAdminRandomLedgerId =
protected val canReadAsAdminRandomLedgerId: Option[String] =
Option(toHeader(forLedgerId(UUID.randomUUID.toString, adminToken)))
protected val canReadAsAdminActualParticipantId =
protected val canReadAsAdminActualParticipantId: Option[String] =
Option(toHeader(forParticipantId("sandbox-participant", adminToken)))
protected val canReadAsAdminRandomParticipantId =
protected val canReadAsAdminRandomParticipantId: Option[String] =
Option(toHeader(forParticipantId(UUID.randomUUID.toString, adminToken)))

}
Loading

0 comments on commit 30564a7

Please sign in to comment.