mirror of
https://github.com/digital-asset/daml.git
synced 2024-09-20 01:07:18 +03:00
use more domain models for json-api response tests (#14101)
CHANGELOG_BEGIN CHANGELOG_END
This commit is contained in:
parent
2ac54ce1f4
commit
7c23420876
@ -533,21 +533,4 @@ object HttpServiceTestFixture extends LazyLogging with Assertions with Inside {
|
||||
|
||||
domain.CreateCommand(templateId, arg, None)
|
||||
}
|
||||
|
||||
def getContractId(result: JsValue): domain.ContractId =
|
||||
inside(result.asJsObject.fields.get("contractId")) { case Some(JsString(contractId)) =>
|
||||
domain.ContractId(contractId)
|
||||
}
|
||||
|
||||
def getResult(output: JsValue): JsValue = getChild(output, "result")
|
||||
|
||||
def getWarnings(output: JsValue): JsValue = getChild(output, "warnings")
|
||||
|
||||
def getChild(output: JsValue, field: String): JsValue = {
|
||||
def errorMsg = s"Expected JsObject with '$field' field, got: $output"
|
||||
output
|
||||
.asJsObject(errorMsg)
|
||||
.fields
|
||||
.getOrElse(field, fail(errorMsg))
|
||||
}
|
||||
}
|
||||
|
@ -418,6 +418,21 @@ abstract class FailureTests
|
||||
|
||||
}
|
||||
|
||||
private[this] def getResult(output: JsValue): JsValue = getChild(output, "result")
|
||||
|
||||
private[this] def getChild(output: JsValue, field: String): JsValue = {
|
||||
def errorMsg = s"Expected JsObject with '$field' field, got: $output"
|
||||
output
|
||||
.asJsObject(errorMsg)
|
||||
.fields
|
||||
.getOrElse(field, fail(errorMsg))
|
||||
}
|
||||
|
||||
def getContractId(result: JsValue): domain.ContractId =
|
||||
inside(result.asJsObject.fields.get("contractId")) { case Some(JsString(contractId)) =>
|
||||
domain.ContractId(contractId)
|
||||
}
|
||||
|
||||
// TEST_EVIDENCE: Semantics: fromStartupMode should not succeed for any input when the db connection is broken
|
||||
"fromStartupMode should not succeed for any input when the connection to the db is broken" in {
|
||||
import cats.effect.IO
|
||||
|
@ -88,20 +88,21 @@ abstract class HttpServiceIntegrationTest
|
||||
fixture,
|
||||
aliceHeaders,
|
||||
)
|
||||
testIIouID = {
|
||||
discard { createTest._1 should ===(StatusCodes.OK) }
|
||||
createTest._2.convertTo[domain.OkResponse[domain.ActiveContract[JsValue]]].result.contractId
|
||||
testIIouID = inside(createTest) { case (StatusCodes.OK, domain.OkResponse(result, _, _)) =>
|
||||
result.contractId
|
||||
}
|
||||
bobH <- fixture.getUniquePartyAndAuthHeaders("Bob")
|
||||
(bob, _) = bobH
|
||||
exerciseTest <- fixture.postJsonRequest(
|
||||
Uri.Path("/v1/exercise"),
|
||||
encodeExercise(encoder)(
|
||||
iouTransfer(domain.EnrichedContractId(Some(exerciseBy), testIIouID), bob)
|
||||
),
|
||||
aliceHeaders,
|
||||
)
|
||||
} yield inside((exerciseTest._1, exerciseTest._2.convertTo[domain.SyncResponse[JsValue]])) {
|
||||
exerciseTest <- fixture
|
||||
.postJsonRequest(
|
||||
Uri.Path("/v1/exercise"),
|
||||
encodeExercise(encoder)(
|
||||
iouTransfer(domain.EnrichedContractId(Some(exerciseBy), testIIouID), bob)
|
||||
),
|
||||
aliceHeaders,
|
||||
)
|
||||
.parseResponse[JsValue]
|
||||
} yield inside(exerciseTest) {
|
||||
case (StatusCodes.OK, domain.OkResponse(_, None, StatusCodes.OK)) => succeed
|
||||
}
|
||||
|
||||
@ -139,26 +140,27 @@ abstract class HttpServiceIntegrationTest
|
||||
_ = createTest._1 should ===(StatusCodes.OK)
|
||||
bobH <- fixture.getUniquePartyAndAuthHeaders("Bob")
|
||||
(bob, _) = bobH
|
||||
exerciseTest <- fixture.postJsonRequest(
|
||||
Uri.Path("/v1/exercise"),
|
||||
encodeExercise(encoder)(
|
||||
iouTransfer(
|
||||
domain.EnrichedContractKey(
|
||||
TpId.IIou.IIou,
|
||||
v.Value(v.Value.Sum.Party(domain.Party unwrap alice)),
|
||||
),
|
||||
bob,
|
||||
)
|
||||
),
|
||||
aliceHeaders,
|
||||
)
|
||||
} yield {
|
||||
val Status = StatusCodes.BadRequest
|
||||
discard { exerciseTest._1 should ===(Status) }
|
||||
inside(exerciseTest._2.convertTo[domain.ErrorResponse]) {
|
||||
case domain.ErrorResponse(Seq(lookup), None, Status, _) =>
|
||||
lookup should include regex raw"Cannot resolve Template Key type, given: TemplateId\([0-9a-f]{64},IIou,IIou\)"
|
||||
}
|
||||
exerciseTest <- fixture
|
||||
.postJsonRequest(
|
||||
Uri.Path("/v1/exercise"),
|
||||
encodeExercise(encoder)(
|
||||
iouTransfer(
|
||||
domain.EnrichedContractKey(
|
||||
TpId.IIou.IIou,
|
||||
v.Value(v.Value.Sum.Party(domain.Party unwrap alice)),
|
||||
),
|
||||
bob,
|
||||
)
|
||||
),
|
||||
aliceHeaders,
|
||||
)
|
||||
.parseResponse[JsValue]
|
||||
} yield inside(exerciseTest) {
|
||||
case (
|
||||
StatusCodes.BadRequest,
|
||||
domain.ErrorResponse(Seq(lookup), None, StatusCodes.BadRequest, _),
|
||||
) =>
|
||||
lookup should include regex raw"Cannot resolve Template Key type, given: TemplateId\([0-9a-f]{64},IIou,IIou\)"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ package com.daml.http
|
||||
import akka.http.scaladsl.model.headers.Authorization
|
||||
import akka.http.scaladsl.model.{StatusCodes, Uri}
|
||||
import com.daml.fetchcontracts.domain.TemplateId.OptionalPkg
|
||||
import com.daml.http.HttpServiceTestFixture.{UseTls, authorizationHeader, getResult, postRequest}
|
||||
import com.daml.http.HttpServiceTestFixture.{UseTls, authorizationHeader, postRequest}
|
||||
import com.daml.ledger.client.withoutledgerid.{LedgerClient => DamlLedgerClient}
|
||||
import com.daml.http.dbbackend.JdbcConfig
|
||||
import com.daml.http.domain.UserDetails
|
||||
@ -91,18 +91,17 @@ class HttpServiceIntegrationTestUserManagementNoAuth
|
||||
CanActAs(Ref.Party.assertFromString(alice.unwrap))
|
||||
),
|
||||
)
|
||||
(status, output) <- fixture.postJsonRequest(
|
||||
Uri.Path("/v1/create"),
|
||||
input,
|
||||
headers = headersWithUserAuth(user.id),
|
||||
)
|
||||
assertion <- {
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
val activeContract = getResult(output)
|
||||
response <- fixture
|
||||
.postJsonRequest(
|
||||
Uri.Path("/v1/create"),
|
||||
input,
|
||||
headers = headersWithUserAuth(user.id),
|
||||
)
|
||||
.parseResponse[domain.ActiveContract[JsValue]]
|
||||
} yield inside(response) {
|
||||
case (StatusCodes.OK, domain.OkResponse(activeContract, _, StatusCodes.OK)) =>
|
||||
assertActiveContract(activeContract)(command, encoder)
|
||||
}
|
||||
} yield assertion
|
||||
}
|
||||
}
|
||||
|
||||
// TEST_EVIDENCE: Authorization: create IOU should fail if user has no permission
|
||||
@ -119,16 +118,17 @@ class HttpServiceIntegrationTestUserManagementNoAuth
|
||||
CanActAs(Ref.Party.assertFromString(bob.unwrap))
|
||||
),
|
||||
)
|
||||
(status, output) <- fixture.postJsonRequest(
|
||||
Uri.Path("/v1/create"),
|
||||
input,
|
||||
headers = headersWithUserAuth(user.id),
|
||||
)
|
||||
assertion <- {
|
||||
status shouldBe StatusCodes.BadRequest
|
||||
assertStatus(output, StatusCodes.BadRequest)
|
||||
}
|
||||
} yield assertion
|
||||
response <- fixture
|
||||
.postJsonRequest(
|
||||
Uri.Path("/v1/create"),
|
||||
input,
|
||||
headers = headersWithUserAuth(user.id),
|
||||
)
|
||||
.parseResponse[JsValue]
|
||||
} yield inside(response) {
|
||||
case (StatusCodes.BadRequest, domain.ErrorResponse(_, _, StatusCodes.BadRequest, _)) =>
|
||||
succeed
|
||||
}
|
||||
}
|
||||
|
||||
// TEST_EVIDENCE: Authorization: create IOU should fail if overwritten actAs & readAs result in missing permission even if the user would have the rights
|
||||
@ -149,16 +149,17 @@ class HttpServiceIntegrationTestUserManagementNoAuth
|
||||
CanActAs(Ref.Party.assertFromString(bob.unwrap)),
|
||||
),
|
||||
)
|
||||
(status, output) <- fixture.postJsonRequest(
|
||||
Uri.Path("/v1/create"),
|
||||
input,
|
||||
headers = headersWithUserAuth(user.id),
|
||||
)
|
||||
assertion <- {
|
||||
status shouldBe StatusCodes.BadRequest
|
||||
assertStatus(output, StatusCodes.BadRequest)
|
||||
}
|
||||
} yield assertion
|
||||
response <- fixture
|
||||
.postJsonRequest(
|
||||
Uri.Path("/v1/create"),
|
||||
input,
|
||||
headers = headersWithUserAuth(user.id),
|
||||
)
|
||||
.parseResponse[JsValue]
|
||||
} yield inside(response) {
|
||||
case (StatusCodes.BadRequest, domain.ErrorResponse(_, _, StatusCodes.BadRequest, _)) =>
|
||||
succeed
|
||||
}
|
||||
}
|
||||
|
||||
"requesting the user id should be possible via the user endpoint" in withHttpService { fixture =>
|
||||
@ -169,17 +170,20 @@ class HttpServiceIntegrationTestUserManagementNoAuth
|
||||
Ref.UserId.assertFromString(getUniqueUserName("nice.user")),
|
||||
initialRights = List.empty,
|
||||
)
|
||||
(status, output) <- fixture.getRequest(
|
||||
Uri.Path("/v1/user"),
|
||||
headers = headersWithUserAuth(user.id),
|
||||
)
|
||||
(status, output) <- fixture
|
||||
.getRequest(
|
||||
Uri.Path("/v1/user"),
|
||||
headers = headersWithUserAuth(user.id),
|
||||
)
|
||||
.parseResponse[UserDetails]
|
||||
assertion <- {
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
getResult(output).convertTo[UserDetails] shouldEqual UserDetails(
|
||||
user.id,
|
||||
user.primaryParty: Option[String],
|
||||
)
|
||||
inside(output) { case domain.OkResponse(result, _, StatusCodes.OK) =>
|
||||
result shouldEqual UserDetails(
|
||||
user.id,
|
||||
user.primaryParty: Option[String],
|
||||
)
|
||||
}
|
||||
}
|
||||
} yield assertion
|
||||
}
|
||||
@ -197,21 +201,19 @@ class HttpServiceIntegrationTestUserManagementNoAuth
|
||||
CanActAs(Ref.Party.assertFromString(bob.unwrap)),
|
||||
),
|
||||
)
|
||||
(status, output) <- postRequest(
|
||||
response <- postRequest(
|
||||
uri.withPath(Uri.Path("/v1/user/rights")),
|
||||
domain.ListUserRightsRequest(user.id).toJson,
|
||||
headers = headersWithAdminAuth,
|
||||
)
|
||||
assertion <- {
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
getResult(output).convertTo[List[domain.UserRight]] should contain theSameElementsAs
|
||||
).parseResponse[List[domain.UserRight]]
|
||||
} yield inside(response) {
|
||||
case (StatusCodes.OK, domain.OkResponse(result, _, StatusCodes.OK)) =>
|
||||
result should contain theSameElementsAs
|
||||
List[domain.UserRight](
|
||||
domain.CanActAs(alice),
|
||||
domain.CanActAs(bob),
|
||||
)
|
||||
}
|
||||
} yield assertion
|
||||
}
|
||||
}
|
||||
|
||||
"requesting the user rights for the current user should be possible via a GET to the user/rights endpoint" in withHttpService {
|
||||
@ -227,18 +229,21 @@ class HttpServiceIntegrationTestUserManagementNoAuth
|
||||
CanActAs(Ref.Party.assertFromString(bob.unwrap)),
|
||||
),
|
||||
)
|
||||
(status, output) <- fixture.getRequest(
|
||||
Uri.Path("/v1/user/rights"),
|
||||
headers = headersWithUserAuth(user.id),
|
||||
)
|
||||
(status, output) <- fixture
|
||||
.getRequest(
|
||||
Uri.Path("/v1/user/rights"),
|
||||
headers = headersWithUserAuth(user.id),
|
||||
)
|
||||
.parseResponse[List[domain.UserRight]]
|
||||
assertion <- {
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
getResult(output).convertTo[List[domain.UserRight]] should contain theSameElementsAs
|
||||
List[domain.UserRight](
|
||||
domain.CanActAs(alice),
|
||||
domain.CanActAs(bob),
|
||||
)
|
||||
inside(output) { case domain.OkResponse(result, _, StatusCodes.OK) =>
|
||||
result should contain theSameElementsAs
|
||||
List[domain.UserRight](
|
||||
domain.CanActAs(alice),
|
||||
domain.CanActAs(bob),
|
||||
)
|
||||
}
|
||||
}
|
||||
} yield assertion
|
||||
}
|
||||
@ -258,14 +263,13 @@ class HttpServiceIntegrationTestUserManagementNoAuth
|
||||
),
|
||||
)
|
||||
for {
|
||||
(status, output) <- postRequest(
|
||||
response <- postRequest(
|
||||
uri.withPath(Uri.Path("/v1/user/create")),
|
||||
createUserRequest.toJson,
|
||||
headers = headersWithAdminAuth,
|
||||
)
|
||||
} yield {
|
||||
status shouldBe StatusCodes.OK
|
||||
getResult(output) shouldBe JsObject()
|
||||
).parseResponse[JsValue]
|
||||
} yield inside(response) { case (StatusCodes.OK, domain.OkResponse(r, _, _)) =>
|
||||
r shouldBe JsObject()
|
||||
}
|
||||
}
|
||||
|
||||
@ -274,27 +278,28 @@ class HttpServiceIntegrationTestUserManagementNoAuth
|
||||
import spray.json._
|
||||
val username = getUniqueUserName("nice.user")
|
||||
for {
|
||||
(status, output) <- postRequest(
|
||||
(status, _) <- postRequest(
|
||||
uri.withPath(Uri.Path("/v1/user/create")),
|
||||
JsObject("userId" -> JsString(username)),
|
||||
headers = headersWithAdminAuth,
|
||||
)
|
||||
_ <- status shouldBe StatusCodes.OK
|
||||
(status2, output2) <- postRequest(
|
||||
response2 <- postRequest(
|
||||
uri.withPath(Uri.Path("/v1/user")),
|
||||
domain.GetUserRequest(username).toJson,
|
||||
headers = headersWithAdminAuth,
|
||||
)
|
||||
_ <- status2 shouldBe StatusCodes.OK
|
||||
_ <- getResult(output2).convertTo[UserDetails] shouldEqual UserDetails(username, None)
|
||||
(status3, output3) <- postRequest(
|
||||
).parseResponse[UserDetails]
|
||||
_ <- inside(response2) { case (StatusCodes.OK, domain.OkResponse(ud, _, _)) =>
|
||||
ud shouldEqual UserDetails(username, None)
|
||||
}
|
||||
response3 <- postRequest(
|
||||
uri.withPath(Uri.Path("/v1/user/rights")),
|
||||
domain.ListUserRightsRequest(username).toJson,
|
||||
headers = headersWithAdminAuth,
|
||||
)
|
||||
_ <- status3 shouldBe StatusCodes.OK
|
||||
} yield getResult(output3)
|
||||
.convertTo[List[domain.UserRight]] shouldEqual List.empty
|
||||
).parseResponse[List[domain.UserRight]]
|
||||
} yield inside(response3) { case (StatusCodes.OK, domain.OkResponse(List(), _, _)) =>
|
||||
succeed
|
||||
}
|
||||
}
|
||||
|
||||
"getting all users should be possible via the users endpoint" in withHttpService { fixture =>
|
||||
@ -328,13 +333,15 @@ class HttpServiceIntegrationTestUserManagementNoAuth
|
||||
_ = status shouldBe StatusCodes.OK
|
||||
} yield ()
|
||||
)
|
||||
(status, output) <- fixture.getRequest(
|
||||
Uri.Path("/v1/users"),
|
||||
headers = headersWithAdminAuth,
|
||||
)
|
||||
_ = status shouldBe StatusCodes.OK
|
||||
users = getResult(output).convertTo[List[UserDetails]]
|
||||
} yield users.map(_.userId) should contain allElementsOf usernames
|
||||
(status, result) <- fixture
|
||||
.getRequest(
|
||||
Uri.Path("/v1/users"),
|
||||
headers = headersWithAdminAuth,
|
||||
)
|
||||
.parseResponse[List[UserDetails]]
|
||||
} yield inside((status, result)) { case (StatusCodes.OK, domain.OkResponse(users, _, _)) =>
|
||||
users.map(_.userId) should contain allElementsOf usernames
|
||||
}
|
||||
}
|
||||
|
||||
"getting information about a specific user should be possible via the user endpoint" in withHttpServiceAndClient {
|
||||
@ -352,23 +359,21 @@ class HttpServiceIntegrationTestUserManagementNoAuth
|
||||
),
|
||||
)
|
||||
for {
|
||||
(status1, output1) <- postRequest(
|
||||
response1 <- postRequest(
|
||||
uri.withPath(Uri.Path("/v1/user/create")),
|
||||
createUserRequest.toJson,
|
||||
headers = headersWithAdminAuth,
|
||||
)
|
||||
_ <- {
|
||||
status1 shouldBe StatusCodes.OK
|
||||
getResult(output1) shouldBe JsObject()
|
||||
).parseResponse[JsValue]
|
||||
_ <- inside(response1) { case (StatusCodes.OK, domain.OkResponse(r, _, _)) =>
|
||||
r shouldBe JsObject()
|
||||
}
|
||||
(status2, output2) <- postRequest(
|
||||
response2 <- postRequest(
|
||||
uri.withPath(Uri.Path(s"/v1/user")),
|
||||
domain.GetUserRequest(createUserRequest.userId).toJson,
|
||||
headers = headersWithAdminAuth,
|
||||
)
|
||||
} yield {
|
||||
status2 shouldBe StatusCodes.OK
|
||||
getResult(output2).convertTo[UserDetails] shouldBe UserDetails(
|
||||
).parseResponse[UserDetails]
|
||||
} yield inside(response2) { case (StatusCodes.OK, domain.OkResponse(ud, _, _)) =>
|
||||
ud shouldBe UserDetails(
|
||||
createUserRequest.userId,
|
||||
createUserRequest.primaryParty,
|
||||
)
|
||||
@ -391,22 +396,22 @@ class HttpServiceIntegrationTestUserManagementNoAuth
|
||||
),
|
||||
)
|
||||
for {
|
||||
(status1, output1) <- postRequest(
|
||||
response1 <- postRequest(
|
||||
uri.withPath(Uri.Path("/v1/user/create")),
|
||||
createUserRequest.toJson,
|
||||
headers = headersWithAdminAuth,
|
||||
)
|
||||
_ <- {
|
||||
status1 shouldBe StatusCodes.OK
|
||||
getResult(output1) shouldBe JsObject()
|
||||
).parseResponse[JsValue]
|
||||
_ <- inside(response1) { case (StatusCodes.OK, domain.OkResponse(r, _, _)) =>
|
||||
r shouldBe JsObject()
|
||||
}
|
||||
(status2, output2) <- fixture.getRequest(
|
||||
Uri.Path(s"/v1/user"),
|
||||
headers = headersWithUserAuth(createUserRequest.userId),
|
||||
)
|
||||
} yield {
|
||||
status2 shouldBe StatusCodes.OK
|
||||
getResult(output2).convertTo[UserDetails] shouldBe UserDetails(
|
||||
response2 <- fixture
|
||||
.getRequest(
|
||||
Uri.Path(s"/v1/user"),
|
||||
headers = headersWithUserAuth(createUserRequest.userId),
|
||||
)
|
||||
.parseResponse[UserDetails]
|
||||
} yield inside(response2) { case (StatusCodes.OK, domain.OkResponse(userDetails, _, _)) =>
|
||||
userDetails shouldBe UserDetails(
|
||||
createUserRequest.userId,
|
||||
createUserRequest.primaryParty,
|
||||
)
|
||||
@ -430,14 +435,13 @@ class HttpServiceIntegrationTestUserManagementNoAuth
|
||||
),
|
||||
)
|
||||
for {
|
||||
(status1, output1) <- postRequest(
|
||||
response1 <- postRequest(
|
||||
uri.withPath(Uri.Path("/v1/user/create")),
|
||||
createUserRequest.toJson,
|
||||
headers = headersWithAdminAuth,
|
||||
)
|
||||
_ <- {
|
||||
status1 shouldBe StatusCodes.OK
|
||||
getResult(output1) shouldBe JsObject()
|
||||
).parseResponse[JsValue]
|
||||
_ <- inside(response1) { case (StatusCodes.OK, domain.OkResponse(r, _, _)) =>
|
||||
r shouldBe JsObject()
|
||||
}
|
||||
(status2, _) <- postRequest(
|
||||
uri.withPath(Uri.Path(s"/v1/user/delete")),
|
||||
@ -445,13 +449,14 @@ class HttpServiceIntegrationTestUserManagementNoAuth
|
||||
headers = headersWithAdminAuth,
|
||||
)
|
||||
_ = status2 shouldBe StatusCodes.OK
|
||||
(status3, output3) <- fixture.getRequest(
|
||||
Uri.Path("/v1/users"),
|
||||
headers = headersWithAdminAuth,
|
||||
)
|
||||
} yield {
|
||||
status3 shouldBe StatusCodes.OK
|
||||
getResult(output3).convertTo[List[UserDetails]] should not contain createUserRequest.userId
|
||||
response3 <- fixture
|
||||
.getRequest(
|
||||
Uri.Path("/v1/users"),
|
||||
headers = headersWithAdminAuth,
|
||||
)
|
||||
.parseResponse[List[UserDetails]]
|
||||
} yield inside(response3) { case (StatusCodes.OK, domain.OkResponse(users, _, _)) =>
|
||||
users should not contain createUserRequest.userId
|
||||
}
|
||||
}
|
||||
|
||||
@ -467,7 +472,7 @@ class HttpServiceIntegrationTestUserManagementNoAuth
|
||||
CanActAs(Ref.Party.assertFromString(alice.unwrap))
|
||||
),
|
||||
)
|
||||
(status, output) <- postRequest(
|
||||
response <- postRequest(
|
||||
uri.withPath(Uri.Path("/v1/user/rights/grant")),
|
||||
domain
|
||||
.GrantUserRightsRequest(
|
||||
@ -480,28 +485,25 @@ class HttpServiceIntegrationTestUserManagementNoAuth
|
||||
)
|
||||
.toJson,
|
||||
headers = headersWithAdminAuth,
|
||||
)
|
||||
_ <- {
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
getResult(output).convertTo[List[domain.UserRight]] should contain theSameElementsAs List[
|
||||
).parseResponse[List[domain.UserRight]]
|
||||
_ <- inside(response) { case (StatusCodes.OK, domain.OkResponse(urs, _, StatusCodes.OK)) =>
|
||||
urs should contain theSameElementsAs List[
|
||||
domain.UserRight
|
||||
](domain.CanActAs(bob), domain.ParticipantAdmin)
|
||||
}
|
||||
(status2, output2) <- postRequest(
|
||||
response2 <- postRequest(
|
||||
uri.withPath(Uri.Path("/v1/user/rights")),
|
||||
domain.ListUserRightsRequest(user.id).toJson,
|
||||
headers = headersWithAdminAuth,
|
||||
)
|
||||
assertion <- {
|
||||
status2 shouldBe StatusCodes.OK
|
||||
assertStatus(output2, StatusCodes.OK)
|
||||
getResult(output2).convertTo[List[domain.UserRight]] should contain theSameElementsAs
|
||||
List[domain.UserRight](
|
||||
domain.CanActAs(alice),
|
||||
domain.CanActAs(bob),
|
||||
domain.ParticipantAdmin,
|
||||
)
|
||||
).parseResponse[List[domain.UserRight]]
|
||||
assertion <- inside(response2) {
|
||||
case (StatusCodes.OK, domain.OkResponse(urs, _, StatusCodes.OK)) =>
|
||||
urs should contain theSameElementsAs
|
||||
List[domain.UserRight](
|
||||
domain.CanActAs(alice),
|
||||
domain.CanActAs(bob),
|
||||
domain.ParticipantAdmin,
|
||||
)
|
||||
}
|
||||
} yield assertion
|
||||
}
|
||||
@ -521,7 +523,7 @@ class HttpServiceIntegrationTestUserManagementNoAuth
|
||||
ParticipantAdmin,
|
||||
),
|
||||
)
|
||||
(status, output) <- postRequest(
|
||||
response <- postRequest(
|
||||
uri.withPath(Uri.Path("/v1/user/rights/revoke")),
|
||||
domain
|
||||
.RevokeUserRightsRequest(
|
||||
@ -534,32 +536,22 @@ class HttpServiceIntegrationTestUserManagementNoAuth
|
||||
)
|
||||
.toJson,
|
||||
headers = headersWithAdminAuth,
|
||||
)
|
||||
_ <- {
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
getResult(output)
|
||||
.convertTo[List[domain.UserRight]] should contain theSameElementsAs List[
|
||||
domain.UserRight
|
||||
](
|
||||
).parseResponse[List[domain.UserRight]]
|
||||
_ <- inside(response) { case (StatusCodes.OK, domain.OkResponse(urs, _, StatusCodes.OK)) =>
|
||||
urs should contain theSameElementsAs List[domain.UserRight](
|
||||
domain.CanActAs(bob),
|
||||
domain.ParticipantAdmin,
|
||||
)
|
||||
}
|
||||
(status2, output2) <- postRequest(
|
||||
response2 <- postRequest(
|
||||
uri.withPath(Uri.Path("/v1/user/rights")),
|
||||
domain.ListUserRightsRequest(user.id).toJson,
|
||||
headers = headersWithAdminAuth,
|
||||
)
|
||||
assertion <- {
|
||||
status2 shouldBe StatusCodes.OK
|
||||
assertStatus(output2, StatusCodes.OK)
|
||||
getResult(output2).convertTo[List[domain.UserRight]] should contain theSameElementsAs
|
||||
List[domain.UserRight](
|
||||
domain.CanActAs(alice)
|
||||
)
|
||||
}
|
||||
} yield assertion
|
||||
).parseResponse[List[domain.UserRight]]
|
||||
} yield inside(response2) {
|
||||
case (StatusCodes.OK, domain.OkResponse(urs, _, StatusCodes.OK)) =>
|
||||
urs should contain theSameElementsAs List[domain.UserRight](domain.CanActAs(alice))
|
||||
}
|
||||
}
|
||||
|
||||
// TEST_EVIDENCE: Performance: creating and listing 20K users should be possible
|
||||
@ -615,13 +607,14 @@ class HttpServiceIntegrationTestUserManagementNoAuth
|
||||
|
||||
for {
|
||||
_ <- createUsers(createUserRequests)
|
||||
(status, output) <- fixture.getRequest(
|
||||
Uri.Path("/v1/users"),
|
||||
headers = headersWithAdminAuth,
|
||||
)
|
||||
} yield {
|
||||
status shouldBe StatusCodes.OK
|
||||
val userIds = getResult(output).convertTo[List[UserDetails]].map(_.userId)
|
||||
response <- fixture
|
||||
.getRequest(
|
||||
Uri.Path("/v1/users"),
|
||||
headers = headersWithAdminAuth,
|
||||
)
|
||||
.parseResponse[List[UserDetails]]
|
||||
} yield inside(response) { case (StatusCodes.OK, domain.OkResponse(users, _, _)) =>
|
||||
val userIds = users.map(_.userId)
|
||||
val expectedUserIds = "participant_admin" :: createUserRequests.map(_.userId)
|
||||
userIds should contain allElementsOf expectedUserIds
|
||||
}
|
||||
|
@ -15,10 +15,9 @@ import com.daml.http.endpoints.MeteringReportEndpoint.{
|
||||
MeteringReportDateRequest,
|
||||
MeteringReportRequest,
|
||||
}
|
||||
import com.daml.http.json.SprayJson.{decode, decode1, objectField}
|
||||
import com.daml.http.json.SprayJson.objectField
|
||||
import com.daml.http.json._
|
||||
import com.daml.http.util.ClientUtil.{boxedRecord, uniqueId}
|
||||
import com.daml.http.util.FutureUtil
|
||||
import com.daml.jwt.domain.Jwt
|
||||
import com.daml.ledger.api.refinements.{ApiTypes => lar}
|
||||
import com.daml.ledger.api.v1.{value => v}
|
||||
@ -83,19 +82,13 @@ trait AbstractHttpServiceIntegrationTestFunsCustomToken
|
||||
Uri.Path("/v1/parties"),
|
||||
headersWithPartyAuthLegacyFormat(List()),
|
||||
)
|
||||
.flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
inside(
|
||||
decode1[domain.OkResponse, List[domain.PartyDetails]](output)
|
||||
) { case \/-(response) =>
|
||||
response.status shouldBe StatusCodes.OK
|
||||
response.warnings shouldBe empty
|
||||
val actualIds: Set[domain.Party] = response.result.view.map(_.identifier).toSet
|
||||
actualIds should contain allElementsOf domain.Party.subst(partyIds.toSet)
|
||||
response.result.toSet should contain allElementsOf
|
||||
allocatedParties.toSet.map(domain.PartyDetails.fromLedgerApi)
|
||||
}
|
||||
}
|
||||
.parseResponse[List[domain.PartyDetails]]
|
||||
.map(inside(_) { case (StatusCodes.OK, domain.OkResponse(result, None, StatusCodes.OK)) =>
|
||||
val actualIds: Set[domain.Party] = result.view.map(_.identifier).toSet
|
||||
actualIds should contain allElementsOf domain.Party.subst(partyIds.toSet)
|
||||
result.toSet should contain allElementsOf
|
||||
allocatedParties.toSet.map(domain.PartyDetails.fromLedgerApi)
|
||||
})
|
||||
}: Future[Assertion]
|
||||
}
|
||||
|
||||
@ -115,15 +108,14 @@ trait AbstractHttpServiceIntegrationTestFunsCustomToken
|
||||
input,
|
||||
headers,
|
||||
)
|
||||
.flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.Unauthorized
|
||||
assertStatus(output, StatusCodes.Unauthorized)
|
||||
HttpServiceTestFixture.getChild(
|
||||
output,
|
||||
"errors",
|
||||
) shouldBe JsArray(JsString("ledgerId missing in access token"))
|
||||
|
||||
}: Future[Assertion]
|
||||
.parseResponse[JsValue]
|
||||
.map(inside(_) {
|
||||
case (
|
||||
StatusCodes.Unauthorized,
|
||||
domain.ErrorResponse(Seq(error), _, StatusCodes.Unauthorized, _),
|
||||
) =>
|
||||
error shouldBe "ledgerId missing in access token"
|
||||
}): Future[Assertion]
|
||||
}
|
||||
|
||||
"metering-report endpoint should return metering report" in withHttpService { fixture =>
|
||||
@ -165,21 +157,14 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
UriFixture,
|
||||
HttpServiceTestFixtureData,
|
||||
}
|
||||
import HttpServiceTestFixture.{
|
||||
UseTls,
|
||||
accountCreateCommand,
|
||||
getResult,
|
||||
getContractId,
|
||||
archiveCommand,
|
||||
getChild,
|
||||
}
|
||||
import HttpServiceTestFixture.{UseTls, accountCreateCommand, archiveCommand}
|
||||
import json.JsonProtocol._
|
||||
|
||||
override def useTls = UseTls.NoTls
|
||||
|
||||
"query GET empty results" in withHttpService { fixture =>
|
||||
fixture.getUniquePartyAndAuthHeaders("Alice").flatMap { case (_, headers) =>
|
||||
fixture.searchAllExpectOk(headers).flatMap { case vector =>
|
||||
fixture.searchAllExpectOk(headers).map { vector =>
|
||||
vector should have size 0L
|
||||
}
|
||||
}
|
||||
@ -205,15 +190,10 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
|
||||
fixture
|
||||
.getRequest(Uri.Path("/v1/query"), headers)
|
||||
.flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
inside(output) { case JsObject(fields) =>
|
||||
inside(fields.get("result")) { case Some(JsArray(vector)) =>
|
||||
vector should have size searchDataSet.size.toLong
|
||||
}
|
||||
}
|
||||
}: Future[Assertion]
|
||||
.parseResponse[Vector[JsValue]]
|
||||
.map(inside(_) { case (StatusCodes.OK, domain.OkResponse(vector, None, StatusCodes.OK)) =>
|
||||
vector should have size searchDataSet.size.toLong
|
||||
}): Future[Assertion]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -370,7 +350,7 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
fixture.getUniquePartyAndAuthHeaders("Alice").flatMap { case (alice, headers) =>
|
||||
val searchDataSet = genSearchDataSet(alice)
|
||||
searchDataSet.traverse(c => postCreateCommand(c, fixture, headers)).flatMap {
|
||||
rs: List[(StatusCode, JsValue)] =>
|
||||
rs: List[(StatusCode, _)] =>
|
||||
rs.map(_._1) shouldBe List.fill(searchDataSet.size)(StatusCodes.OK)
|
||||
|
||||
def queryAmountAs(s: String) =
|
||||
@ -379,21 +359,22 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
val queryAmountAsString = queryAmountAs("\"111.11\"")
|
||||
val queryAmountAsNumber = queryAmountAs("111.11")
|
||||
|
||||
List(
|
||||
fixture.postJsonRequest(Uri.Path("/v1/query"), queryAmountAsString, headers),
|
||||
fixture.postJsonRequest(Uri.Path("/v1/query"), queryAmountAsNumber, headers),
|
||||
).sequence.flatMap { rs: List[(StatusCode, JsValue)] =>
|
||||
rs.map(_._1) shouldBe List.fill(2)(StatusCodes.OK)
|
||||
inside(rs.map(_._2)) { case List(jsVal1, jsVal2) =>
|
||||
jsVal1 shouldBe jsVal2
|
||||
val acl1: List[domain.ActiveContract[JsValue]] = activeContractList(jsVal1)
|
||||
val acl2: List[domain.ActiveContract[JsValue]] = activeContractList(jsVal2)
|
||||
acl1 shouldBe acl2
|
||||
inside(acl1) { case List(ac) =>
|
||||
List(queryAmountAsString, queryAmountAsNumber)
|
||||
.map(q =>
|
||||
fixture
|
||||
.postJsonRequest(Uri.Path("/v1/query"), q, headers)
|
||||
.parseResponse[List[domain.ActiveContract[JsValue]]]
|
||||
)
|
||||
.sequence
|
||||
.map(inside(_) {
|
||||
case Seq(
|
||||
(StatusCodes.OK, jsVal1 @ domain.OkResponse(acl1 @ List(ac), _, _)),
|
||||
(StatusCodes.OK, jsVal2 @ domain.OkResponse(acl2, _, _)),
|
||||
) =>
|
||||
jsVal1 shouldBe jsVal2
|
||||
acl1 shouldBe acl2
|
||||
objectField(ac.payload, "amount") shouldBe Some(JsString("111.11"))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}: Future[Assertion]
|
||||
}
|
||||
}
|
||||
@ -470,10 +451,11 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
"query with invalid JSON query should return error" in withHttpService { fixture =>
|
||||
fixture
|
||||
.postJsonStringRequest(Uri.Path("/v1/query"), "{NOT A VALID JSON OBJECT")
|
||||
.flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.BadRequest
|
||||
assertStatus(output, StatusCodes.BadRequest)
|
||||
}: Future[Assertion]
|
||||
.parseResponse[JsValue]
|
||||
.map(inside(_) {
|
||||
case (StatusCodes.BadRequest, domain.ErrorResponse(_, _, StatusCodes.BadRequest, _)) =>
|
||||
succeed
|
||||
}): Future[Assertion]
|
||||
}
|
||||
|
||||
"fail to query by interface ID" in withHttpService { fixture =>
|
||||
@ -514,15 +496,11 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
|
||||
def searchAll(
|
||||
headers: List[HttpHeader]
|
||||
): Future[domain.SyncResponse[List[domain.ActiveContract[JsValue]]]] = {
|
||||
): Future[domain.SyncResponse[List[domain.ActiveContract[JsValue]]]] =
|
||||
fixture
|
||||
.getRequest(Uri.Path("/v1/query"), headers)
|
||||
.flatMap { case (_, output) =>
|
||||
FutureUtil.toFuture(
|
||||
decode1[domain.SyncResponse, List[domain.ActiveContract[JsValue]]](output)
|
||||
)
|
||||
}
|
||||
}
|
||||
.parseResponse[List[domain.ActiveContract[JsValue]]]
|
||||
.map { case (_, output) => output }
|
||||
|
||||
}
|
||||
|
||||
@ -531,12 +509,11 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
fixture.getUniquePartyAndAuthHeaders("Alice").flatMap { case (alice, headers) =>
|
||||
val command: domain.CreateCommand[v.Record, OptionalPkg] = iouCreateCommand(alice.unwrap)
|
||||
|
||||
postCreateCommand(command, fixture, headers).flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
val activeContract = getResult(output)
|
||||
assertActiveContract(activeContract)(command, encoder)
|
||||
}: Future[Assertion]
|
||||
postCreateCommand(command, fixture, headers)
|
||||
.map(inside(_) {
|
||||
case (StatusCodes.OK, domain.OkResponse(activeContract, _, StatusCodes.OK)) =>
|
||||
assertActiveContract(activeContract)(command, encoder)
|
||||
}): Future[Assertion]
|
||||
}
|
||||
}
|
||||
|
||||
@ -547,14 +524,18 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
val command: domain.CreateCommand[v.Record, OptionalPkg] = iouCreateCommand(alice.unwrap)
|
||||
val input: JsValue = encoder.encodeCreateCommand(command).valueOr(e => fail(e.shows))
|
||||
|
||||
fixture.postJsonRequest(Uri.Path("/v1/create"), input, List()).flatMap {
|
||||
case (status, output) =>
|
||||
status shouldBe StatusCodes.Unauthorized
|
||||
assertStatus(output, StatusCodes.Unauthorized)
|
||||
expectedOneErrorMessage(output) should include(
|
||||
"missing Authorization header with OAuth 2.0 Bearer Token"
|
||||
)
|
||||
}: Future[Assertion]
|
||||
fixture
|
||||
.postJsonRequest(Uri.Path("/v1/create"), input, List())
|
||||
.parseResponse[JsValue]
|
||||
.map(inside(_) {
|
||||
case (
|
||||
StatusCodes.Unauthorized,
|
||||
domain.ErrorResponse(Seq(error), _, StatusCodes.Unauthorized, _),
|
||||
) =>
|
||||
error should include(
|
||||
"missing Authorization header with OAuth 2.0 Bearer Token"
|
||||
)
|
||||
}): Future[Assertion]
|
||||
}
|
||||
|
||||
"create IOU should support extra readAs parties" in withHttpService { fixture =>
|
||||
@ -566,18 +547,18 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
fixture
|
||||
.headersWithPartyAuth(actAs = List(alice.unwrap), readAs = List("Bob"))
|
||||
.flatMap(
|
||||
fixture.postJsonRequest(
|
||||
Uri.Path("/v1/create"),
|
||||
input,
|
||||
_,
|
||||
)
|
||||
fixture
|
||||
.postJsonRequest(
|
||||
Uri.Path("/v1/create"),
|
||||
input,
|
||||
_,
|
||||
)
|
||||
.parseResponse[domain.ActiveContract[JsValue]]
|
||||
)
|
||||
.flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
val activeContract = getResult(output)
|
||||
assertActiveContract(activeContract)(command, encoder)
|
||||
}: Future[Assertion]
|
||||
.map(inside(_) {
|
||||
case (StatusCodes.OK, domain.OkResponse(activeContract, _, StatusCodes.OK)) =>
|
||||
assertActiveContract(activeContract)(command, encoder)
|
||||
}): Future[Assertion]
|
||||
}
|
||||
|
||||
"create IOU with unsupported templateId should return proper error" in withHttpService {
|
||||
@ -588,16 +569,21 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
iouCreateCommand(alice.unwrap).copy(templateId = domain.TemplateId(None, "Iou", "Dummy"))
|
||||
val input: JsValue = encoder.encodeCreateCommand(command).valueOr(e => fail(e.shows))
|
||||
|
||||
fixture.postJsonRequest(Uri.Path("/v1/create"), input, headers).flatMap {
|
||||
case (status, output) =>
|
||||
status shouldBe StatusCodes.BadRequest
|
||||
assertStatus(output, StatusCodes.BadRequest)
|
||||
val unknownTemplateId: OptionalPkg =
|
||||
domain.TemplateId(None, command.templateId.moduleName, command.templateId.entityName)
|
||||
expectedOneErrorMessage(output) should include(
|
||||
s"Cannot resolve template ID, given: ${unknownTemplateId: OptionalPkg}"
|
||||
)
|
||||
}: Future[Assertion]
|
||||
fixture
|
||||
.postJsonRequest(Uri.Path("/v1/create"), input, headers)
|
||||
.parseResponse[JsValue]
|
||||
.map(inside(_) {
|
||||
case (
|
||||
StatusCodes.BadRequest,
|
||||
domain.ErrorResponse(Seq(error), _, StatusCodes.BadRequest, _),
|
||||
) =>
|
||||
val unknownTemplateId: OptionalPkg =
|
||||
domain
|
||||
.TemplateId(None, command.templateId.moduleName, command.templateId.entityName)
|
||||
error should include(
|
||||
s"Cannot resolve template ID, given: ${unknownTemplateId: OptionalPkg}"
|
||||
)
|
||||
}): Future[Assertion]
|
||||
}
|
||||
}
|
||||
|
||||
@ -606,29 +592,26 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
fixture.getUniquePartyAndAuthHeaders("Alice").flatMap { case (alice, headers) =>
|
||||
val create: domain.CreateCommand[v.Record, OptionalPkg] = iouCreateCommand(alice.unwrap)
|
||||
postCreateCommand(create, fixture, headers)
|
||||
.flatMap { case (createStatus, createOutput) =>
|
||||
createStatus shouldBe StatusCodes.OK
|
||||
assertStatus(createOutput, StatusCodes.OK)
|
||||
.flatMap(inside(_) {
|
||||
case (StatusCodes.OK, domain.OkResponse(createResult, _, StatusCodes.OK)) =>
|
||||
val exercise: domain.ExerciseCommand[v.Value, domain.EnrichedContractId] =
|
||||
iouExerciseTransferCommand(createResult.contractId)
|
||||
val exerciseJson: JsValue = encodeExercise(encoder)(exercise)
|
||||
|
||||
val contractId = getContractId(getResult(createOutput))
|
||||
val exercise: domain.ExerciseCommand[v.Value, domain.EnrichedContractId] =
|
||||
iouExerciseTransferCommand(contractId)
|
||||
val exerciseJson: JsValue = encodeExercise(encoder)(exercise)
|
||||
|
||||
fixture
|
||||
.postJsonRequest(Uri.Path("/v1/exercise"), exerciseJson, headers)
|
||||
.flatMap { case (exerciseStatus, exerciseOutput) =>
|
||||
exerciseStatus shouldBe StatusCodes.OK
|
||||
assertStatus(exerciseOutput, StatusCodes.OK)
|
||||
assertExerciseResponseNewActiveContract(
|
||||
getResult(exerciseOutput),
|
||||
create,
|
||||
exercise,
|
||||
fixture,
|
||||
headers,
|
||||
)
|
||||
}
|
||||
}: Future[Assertion]
|
||||
fixture
|
||||
.postJsonRequest(Uri.Path("/v1/exercise"), exerciseJson, headers)
|
||||
.parseResponse[domain.ExerciseResponse[JsValue]]
|
||||
.flatMap(inside(_) {
|
||||
case (StatusCodes.OK, domain.OkResponse(result, _, StatusCodes.OK)) =>
|
||||
assertExerciseResponseNewActiveContract(
|
||||
result,
|
||||
create,
|
||||
exercise,
|
||||
fixture,
|
||||
headers,
|
||||
)
|
||||
})
|
||||
}): Future[Assertion]
|
||||
}
|
||||
}
|
||||
|
||||
@ -642,14 +625,10 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
|
||||
fixture
|
||||
.postJsonRequest(Uri.Path("/v1/create-and-exercise"), json, headers)
|
||||
.flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
inside(
|
||||
decode1[domain.OkResponse, domain.ExerciseResponse[JsValue]](output)
|
||||
) { case \/-(response) =>
|
||||
response.status shouldBe StatusCodes.OK
|
||||
response.warnings shouldBe empty
|
||||
inside(response.result.events) {
|
||||
.parseResponse[domain.ExerciseResponse[JsValue]]
|
||||
.flatMap(inside(_) {
|
||||
case (StatusCodes.OK, domain.OkResponse(result, None, StatusCodes.OK)) =>
|
||||
inside(result.events) {
|
||||
case List(
|
||||
domain.Contract(\/-(created0)),
|
||||
domain.Contract(-\/(archived0)),
|
||||
@ -659,23 +638,22 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
assertTemplateId(archived0.templateId, cmd.templateId)
|
||||
archived0.contractId shouldBe created0.contractId
|
||||
assertTemplateId(created1.templateId, TpId.Iou.IouTransfer)
|
||||
asContractId(response.result.exerciseResult) shouldBe created1.contractId
|
||||
asContractId(result.exerciseResult) shouldBe created1.contractId
|
||||
}
|
||||
}
|
||||
}: Future[Assertion]
|
||||
}
|
||||
})
|
||||
}: Future[Assertion]
|
||||
}
|
||||
|
||||
private def assertExerciseResponseNewActiveContract(
|
||||
exerciseResponse: JsValue,
|
||||
exerciseResponse: domain.ExerciseResponse[JsValue],
|
||||
createCmd: domain.CreateCommand[v.Record, OptionalPkg],
|
||||
exerciseCmd: domain.ExerciseCommand[v.Value, domain.EnrichedContractId],
|
||||
fixture: HttpServiceTestFixtureData,
|
||||
headers: List[HttpHeader],
|
||||
): Future[Assertion] = {
|
||||
import fixture.{uri, decoder}
|
||||
inside(SprayJson.decode[domain.ExerciseResponse[JsValue]](exerciseResponse)) {
|
||||
case \/-(domain.ExerciseResponse(JsString(exerciseResult), List(contract1, contract2))) =>
|
||||
inside(exerciseResponse) {
|
||||
case domain.ExerciseResponse(JsString(exerciseResult), List(contract1, contract2)) =>
|
||||
// checking contracts
|
||||
inside(contract1) { case domain.Contract(-\/(archivedContract)) =>
|
||||
Future {
|
||||
@ -692,11 +670,10 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
Some(TpId.Iou.IouTransfer),
|
||||
domain.ContractId(exerciseResult),
|
||||
)
|
||||
postContractsLookup(newContractLocator, uri, headers).flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
getContractId(getResult(output)) shouldBe newContractLocator.contractId
|
||||
}: Future[Assertion]
|
||||
postContractsLookup(newContractLocator, uri, headers).map(inside(_) {
|
||||
case (StatusCodes.OK, domain.OkResponse(Some(contract), _, StatusCodes.OK)) =>
|
||||
contract.contractId shouldBe newContractLocator.contractId
|
||||
}): Future[Assertion]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -746,24 +723,20 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
fixture.getUniquePartyAndAuthHeaders("Alice").flatMap { case (alice, headers) =>
|
||||
val create: domain.CreateCommand[v.Record, OptionalPkg] = iouCreateCommand(alice.unwrap)
|
||||
postCreateCommand(create, fixture, headers)
|
||||
.flatMap { case (createStatus, createOutput) =>
|
||||
createStatus shouldBe StatusCodes.OK
|
||||
assertStatus(createOutput, StatusCodes.OK)
|
||||
.flatMap(inside(_) {
|
||||
case (StatusCodes.OK, domain.OkResponse(createResult, _, StatusCodes.OK)) =>
|
||||
val reference = domain.EnrichedContractId(Some(TpId.Iou.Iou), createResult.contractId)
|
||||
val exercise = archiveCommand(reference)
|
||||
val exerciseJson: JsValue = encodeExercise(encoder)(exercise)
|
||||
|
||||
val contractId = getContractId(getResult(createOutput))
|
||||
val reference = domain.EnrichedContractId(Some(TpId.Iou.Iou), contractId)
|
||||
val exercise = archiveCommand(reference)
|
||||
val exerciseJson: JsValue = encodeExercise(encoder)(exercise)
|
||||
|
||||
fixture
|
||||
.postJsonRequest(Uri.Path("/v1/exercise"), exerciseJson, headers)
|
||||
.flatMap { case (exerciseStatus, exerciseOutput) =>
|
||||
exerciseStatus shouldBe StatusCodes.OK
|
||||
assertStatus(exerciseOutput, StatusCodes.OK)
|
||||
val exercisedResponse: JsObject = getResult(exerciseOutput).asJsObject
|
||||
assertExerciseResponseArchivedContract(exercisedResponse, exercise)
|
||||
}
|
||||
}: Future[Assertion]
|
||||
fixture
|
||||
.postJsonRequest(Uri.Path("/v1/exercise"), exerciseJson, headers)
|
||||
.parseResponse[domain.ExerciseResponse[JsValue]]
|
||||
.flatMap(inside(_) {
|
||||
case (StatusCodes.OK, domain.OkResponse(exercisedResponse, _, StatusCodes.OK)) =>
|
||||
assertExerciseResponseArchivedContract(exercisedResponse, exercise)
|
||||
})
|
||||
}): Future[Assertion]
|
||||
}
|
||||
}
|
||||
|
||||
@ -776,10 +749,9 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
.flatMap(
|
||||
postCreateCommand(multiPartyCreateCommand(List("Alice", "Bob"), ""), fixture, _)
|
||||
)
|
||||
.map { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
getContractId(getResult(output))
|
||||
}
|
||||
.map(inside(_) { case (StatusCodes.OK, domain.OkResponse(result, _, _)) =>
|
||||
result.contractId
|
||||
})
|
||||
// multi-party actAs on exercise
|
||||
cidMulti <- fixture
|
||||
.headersWithPartyAuth(List("Alice", "Bob", "Charlie", "David"))
|
||||
@ -790,12 +762,11 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
_,
|
||||
)
|
||||
)
|
||||
.map { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
inside(getChild(getResult(output), "exerciseResult")) { case JsString(c) =>
|
||||
.parseResponse[domain.ExerciseResponse[JsValue]]
|
||||
.map(inside(_) {
|
||||
case (StatusCodes.OK, domain.OkResponse(domain.ExerciseResponse(JsString(c), _), _, _)) =>
|
||||
lar.ContractId(c)
|
||||
}
|
||||
}
|
||||
})
|
||||
// create a contract only visible to Alice
|
||||
cid <- fixture
|
||||
.headersWithPartyAuth(List("Alice"))
|
||||
@ -806,10 +777,9 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
_,
|
||||
)
|
||||
)
|
||||
.map { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
getContractId(getResult(output))
|
||||
}
|
||||
.map(inside(_) { case (StatusCodes.OK, domain.OkResponse(result, _, _)) =>
|
||||
result.contractId
|
||||
})
|
||||
_ <- fixture
|
||||
.headersWithPartyAuth(List("Charlie"), readAs = List("Alice"))
|
||||
.flatMap(
|
||||
@ -826,19 +796,15 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
}
|
||||
|
||||
private def assertExerciseResponseArchivedContract(
|
||||
exerciseResponse: JsValue,
|
||||
exerciseResponse: domain.ExerciseResponse[JsValue],
|
||||
exercise: domain.ExerciseCommand[v.Value, domain.EnrichedContractId],
|
||||
): Assertion = {
|
||||
inside(exerciseResponse) { case result @ JsObject(_) =>
|
||||
inside(SprayJson.decode[domain.ExerciseResponse[JsValue]](result)) {
|
||||
case \/-(domain.ExerciseResponse(exerciseResult, List(contract1))) =>
|
||||
exerciseResult shouldBe JsObject()
|
||||
inside(contract1) { case domain.Contract(-\/(archivedContract)) =>
|
||||
(archivedContract.contractId.unwrap: String) shouldBe (exercise.reference.contractId.unwrap: String)
|
||||
}
|
||||
): Assertion =
|
||||
inside(exerciseResponse) { case domain.ExerciseResponse(exerciseResult, List(contract1)) =>
|
||||
exerciseResult shouldBe JsObject()
|
||||
inside(contract1) { case domain.Contract(-\/(archivedContract)) =>
|
||||
(archivedContract.contractId.unwrap: String) shouldBe (exercise.reference.contractId.unwrap: String)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"should be able to serialize and deserialize domain commands" in withHttpService { fixture =>
|
||||
(testCreateCommandEncodingDecoding(fixture) *>
|
||||
@ -906,19 +872,13 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
Uri.Path("/v1/parties"),
|
||||
headers = headersWithAdminAuth,
|
||||
)
|
||||
.flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
inside(
|
||||
decode1[domain.OkResponse, List[domain.PartyDetails]](output)
|
||||
) { case \/-(response) =>
|
||||
response.status shouldBe StatusCodes.OK
|
||||
response.warnings shouldBe empty
|
||||
val actualIds: Set[domain.Party] = response.result.view.map(_.identifier).toSet
|
||||
actualIds should contain allElementsOf domain.Party.subst(partyIds.toSet)
|
||||
response.result.toSet should contain allElementsOf
|
||||
allocatedParties.toSet.map(domain.PartyDetails.fromLedgerApi)
|
||||
}
|
||||
}
|
||||
.parseResponse[List[domain.PartyDetails]]
|
||||
.map(inside(_) { case (StatusCodes.OK, domain.OkResponse(result, None, StatusCodes.OK)) =>
|
||||
val actualIds: Set[domain.Party] = result.view.map(_.identifier).toSet
|
||||
actualIds should contain allElementsOf domain.Party.subst(partyIds.toSet)
|
||||
result.toSet should contain allElementsOf
|
||||
allocatedParties.toSet.map(domain.PartyDetails.fromLedgerApi)
|
||||
})
|
||||
}: Future[Assertion]
|
||||
}
|
||||
|
||||
@ -943,21 +903,17 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
JsArray(requestedPartyIds.map(x => JsString(x.unwrap))),
|
||||
headersWithAdminAuth,
|
||||
)
|
||||
.flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
inside(
|
||||
decode1[domain.OkResponse, List[domain.PartyDetails]](output)
|
||||
) { case \/-(response) =>
|
||||
response.status shouldBe StatusCodes.OK
|
||||
response.warnings shouldBe Some(domain.UnknownParties(List(erin)))
|
||||
val actualIds: Set[domain.Party] = response.result.view.map(_.identifier).toSet
|
||||
.parseResponse[List[domain.PartyDetails]]
|
||||
.flatMap(inside(_) {
|
||||
case (StatusCodes.OK, domain.OkResponse(result, Some(warnings), StatusCodes.OK)) =>
|
||||
warnings shouldBe domain.UnknownParties(List(erin))
|
||||
val actualIds: Set[domain.Party] = result.view.map(_.identifier).toSet
|
||||
actualIds shouldBe requestedPartyIds.toSet - erin // Erin is not known
|
||||
val expected: Set[domain.PartyDetails] = allocatedParties.toSet
|
||||
.map(domain.PartyDetails.fromLedgerApi)
|
||||
.filterNot(_.identifier == charlie)
|
||||
response.result.toSet shouldBe expected
|
||||
}
|
||||
}
|
||||
result.toSet shouldBe expected
|
||||
})
|
||||
}: Future[Assertion]
|
||||
}
|
||||
|
||||
@ -1005,15 +961,15 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
JsArray(requestedPartyIds.map(x => JsString(x.unwrap))),
|
||||
headers = headersWithAdminAuth,
|
||||
)
|
||||
.flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
inside(decode1[domain.SyncResponse, List[domain.PartyDetails]](output)) {
|
||||
case \/-(domain.OkResponse(List(), Some(warnings), StatusCodes.OK)) =>
|
||||
inside(warnings) { case domain.UnknownParties(unknownParties) =>
|
||||
unknownParties.toSet shouldBe requestedPartyIds.toSet
|
||||
}
|
||||
}
|
||||
}: Future[Assertion]
|
||||
.parseResponse[List[domain.PartyDetails]]
|
||||
.map(inside(_) {
|
||||
case (
|
||||
StatusCodes.OK,
|
||||
domain
|
||||
.OkResponse(List(), Some(domain.UnknownParties(unknownParties)), StatusCodes.OK),
|
||||
) =>
|
||||
unknownParties.toSet shouldBe requestedPartyIds.toSet
|
||||
}): Future[Assertion]
|
||||
}
|
||||
|
||||
"parties/allocate should allocate a new party" in withHttpService { fixture =>
|
||||
@ -1028,29 +984,21 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
json = json,
|
||||
headers = headersWithAdminAuth,
|
||||
)
|
||||
.flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
inside(decode1[domain.OkResponse, domain.PartyDetails](output)) { case \/-(response) =>
|
||||
response.status shouldBe StatusCodes.OK
|
||||
val newParty = response.result
|
||||
Some(newParty.identifier) shouldBe request.identifierHint
|
||||
newParty.displayName shouldBe request.displayName
|
||||
newParty.isLocal shouldBe true
|
||||
fixture
|
||||
.getRequest(
|
||||
Uri.Path("/v1/parties"),
|
||||
headersWithAdminAuth,
|
||||
)
|
||||
.flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
inside(decode1[domain.OkResponse, List[domain.PartyDetails]](output)) {
|
||||
case \/-(response) =>
|
||||
response.status shouldBe StatusCodes.OK
|
||||
response.result should contain(newParty)
|
||||
}
|
||||
}
|
||||
}
|
||||
}: Future[Assertion]
|
||||
.parseResponse[domain.PartyDetails]
|
||||
.flatMap(inside(_) { case (StatusCodes.OK, domain.OkResponse(newParty, _, StatusCodes.OK)) =>
|
||||
Some(newParty.identifier) shouldBe request.identifierHint
|
||||
newParty.displayName shouldBe request.displayName
|
||||
newParty.isLocal shouldBe true
|
||||
fixture
|
||||
.getRequest(
|
||||
Uri.Path("/v1/parties"),
|
||||
headersWithAdminAuth,
|
||||
)
|
||||
.parseResponse[List[domain.PartyDetails]]
|
||||
.map(inside(_) { case (StatusCodes.OK, domain.OkResponse(result, _, StatusCodes.OK)) =>
|
||||
result should contain(newParty)
|
||||
})
|
||||
}): Future[Assertion]
|
||||
}
|
||||
|
||||
"parties/allocate should allocate a new party without any hints" in withHttpService { fixture =>
|
||||
@ -1060,27 +1008,22 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
json = JsObject(),
|
||||
headers = headersWithAdminAuth,
|
||||
)
|
||||
.flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
inside(decode1[domain.OkResponse, domain.PartyDetails](output)) { case \/-(response) =>
|
||||
response.status shouldBe StatusCodes.OK
|
||||
val newParty = response.result
|
||||
newParty.identifier.unwrap.length should be > 0
|
||||
newParty.displayName shouldBe None
|
||||
newParty.isLocal shouldBe true
|
||||
.parseResponse[domain.PartyDetails]
|
||||
.flatMap(inside(_) { case (StatusCodes.OK, domain.OkResponse(newParty, _, StatusCodes.OK)) =>
|
||||
newParty.identifier.unwrap.length should be > 0
|
||||
newParty.displayName shouldBe None
|
||||
newParty.isLocal shouldBe true
|
||||
|
||||
fixture
|
||||
.getRequest(Uri.Path("/v1/parties"), headers = headersWithAdminAuth)
|
||||
.flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
inside(decode1[domain.OkResponse, List[domain.PartyDetails]](output)) {
|
||||
case \/-(response) =>
|
||||
response.status shouldBe StatusCodes.OK
|
||||
response.result should contain(newParty)
|
||||
}
|
||||
}
|
||||
}
|
||||
}: Future[Assertion]
|
||||
fixture
|
||||
.getRequest(
|
||||
Uri.Path("/v1/parties"),
|
||||
headers = headersWithAdminAuth,
|
||||
)
|
||||
.parseResponse[List[domain.PartyDetails]]
|
||||
.map(inside(_) { case (StatusCodes.OK, domain.OkResponse(result, _, StatusCodes.OK)) =>
|
||||
result should contain(newParty)
|
||||
})
|
||||
}): Future[Assertion]
|
||||
}
|
||||
|
||||
// TEST_EVIDENCE: Authorization: badly-authorized create is rejected
|
||||
@ -1098,27 +1041,26 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
json = json,
|
||||
headers = headersWithAdminAuth,
|
||||
)
|
||||
.flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.BadRequest
|
||||
inside(decode[domain.ErrorResponse](output)) { case \/-(response) =>
|
||||
response.status shouldBe StatusCodes.BadRequest
|
||||
response.warnings shouldBe empty
|
||||
response.errors.length shouldBe 1
|
||||
}
|
||||
}
|
||||
.parseResponse[JsValue]
|
||||
.map(inside(_) {
|
||||
case (
|
||||
StatusCodes.BadRequest,
|
||||
domain.ErrorResponse(errors, None, StatusCodes.BadRequest, _),
|
||||
) =>
|
||||
errors.length shouldBe 1
|
||||
})
|
||||
}
|
||||
|
||||
"fetch by contractId" in withHttpService { fixture =>
|
||||
fixture.getUniquePartyAndAuthHeaders("Alice").flatMap { case (alice, headers) =>
|
||||
val command: domain.CreateCommand[v.Record, OptionalPkg] = iouCreateCommand(alice.unwrap)
|
||||
|
||||
postCreateCommand(command, fixture, headers).flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
val contractId: ContractId = getContractId(getResult(output))
|
||||
val locator = domain.EnrichedContractId(None, contractId)
|
||||
lookupContractAndAssert(locator, contractId, command, fixture, headers)
|
||||
}: Future[Assertion]
|
||||
postCreateCommand(command, fixture, headers).flatMap(inside(_) {
|
||||
case (StatusCodes.OK, domain.OkResponse(result, _, StatusCodes.OK)) =>
|
||||
val contractId: ContractId = result.contractId
|
||||
val locator = domain.EnrichedContractId(None, contractId)
|
||||
lookupContractAndAssert(locator, contractId, command, fixture, headers)
|
||||
}): Future[Assertion]
|
||||
}
|
||||
}
|
||||
|
||||
@ -1131,15 +1073,10 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
TpId.Account.Account,
|
||||
JsArray(JsString(alice.unwrap), JsString(accountNumber)),
|
||||
)
|
||||
postContractsLookup(locator, uri.withPath(Uri.Path("/v1/fetch")), headers).flatMap {
|
||||
case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
output
|
||||
.asJsObject(s"expected JsObject, got: $output")
|
||||
.fields
|
||||
.get("result") shouldBe Some(JsNull)
|
||||
}: Future[Assertion]
|
||||
postContractsLookup(locator, uri.withPath(Uri.Path("/v1/fetch")), headers).map(inside(_) {
|
||||
case (StatusCodes.OK, domain.OkResponse(None, _, StatusCodes.OK)) =>
|
||||
succeed
|
||||
}): Future[Assertion]
|
||||
}
|
||||
}
|
||||
|
||||
@ -1152,11 +1089,9 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
(alice, aliceHeaders) = res
|
||||
command = iouCreateCommand(alice.unwrap)
|
||||
createStatusOutput <- postCreateCommand(command, fixture, aliceHeaders)
|
||||
contractId = {
|
||||
val (status, output) = createStatusOutput
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
getContractId(getResult(output))
|
||||
contractId = inside(createStatusOutput) {
|
||||
case (StatusCodes.OK, domain.OkResponse(result, _, StatusCodes.OK)) =>
|
||||
result.contractId
|
||||
}
|
||||
locator = domain.EnrichedContractId(None, contractId)
|
||||
// will cache if DB configured
|
||||
@ -1168,16 +1103,13 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
aliceHeaders,
|
||||
readAs = Some(List(charlie)),
|
||||
)
|
||||
_ = {
|
||||
val (status, output) = badLookup
|
||||
status shouldBe StatusCodes.Unauthorized
|
||||
assertStatus(output, StatusCodes.Unauthorized)
|
||||
output
|
||||
.asJsObject(s"expected JsObject, got: $output")
|
||||
.fields
|
||||
.keySet should ===(Set("errors", "status"))
|
||||
}
|
||||
} yield succeed
|
||||
} yield inside(badLookup) {
|
||||
case (
|
||||
StatusCodes.Unauthorized,
|
||||
domain.ErrorResponse(_, None, StatusCodes.Unauthorized, None),
|
||||
) =>
|
||||
succeed
|
||||
}
|
||||
}
|
||||
|
||||
"fetch by key" in withHttpService { fixture =>
|
||||
@ -1186,16 +1118,15 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
val command: domain.CreateCommand[v.Record, OptionalPkg] =
|
||||
accountCreateCommand(alice, accountNumber)
|
||||
|
||||
postCreateCommand(command, fixture, headers).flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
val contractId: ContractId = getContractId(getResult(output))
|
||||
val locator = domain.EnrichedContractKey(
|
||||
TpId.Account.Account,
|
||||
JsArray(JsString(alice.unwrap), JsString(accountNumber)),
|
||||
)
|
||||
lookupContractAndAssert(locator, contractId, command, fixture, headers)
|
||||
}: Future[Assertion]
|
||||
postCreateCommand(command, fixture, headers).flatMap(inside(_) {
|
||||
case (StatusCodes.OK, domain.OkResponse(result, _, StatusCodes.OK)) =>
|
||||
val contractId: ContractId = result.contractId
|
||||
val locator = domain.EnrichedContractKey(
|
||||
TpId.Account.Account,
|
||||
JsArray(JsString(alice.unwrap), JsString(accountNumber)),
|
||||
)
|
||||
lookupContractAndAssert(locator, contractId, command, fixture, headers)
|
||||
}): Future[Assertion]
|
||||
}
|
||||
}
|
||||
|
||||
@ -1220,16 +1151,15 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
archiveCommand(locator)
|
||||
val archiveJson: JsValue = encodeExercise(encoder)(archive)
|
||||
|
||||
postCreateCommand(create, fixture, headers).flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
|
||||
fixture.postJsonRequest(Uri.Path("/v1/exercise"), archiveJson, headers).flatMap {
|
||||
case (exerciseStatus, exerciseOutput) =>
|
||||
exerciseStatus shouldBe StatusCodes.OK
|
||||
assertStatus(exerciseOutput, StatusCodes.OK)
|
||||
}
|
||||
}: Future[Assertion]
|
||||
postCreateCommand(create, fixture, headers).flatMap(inside(_) {
|
||||
case (StatusCodes.OK, domain.OkResponse(_, _, StatusCodes.OK)) =>
|
||||
fixture
|
||||
.postJsonRequest(Uri.Path("/v1/exercise"), archiveJson, headers)
|
||||
.parseResponse[JsValue]
|
||||
.map(inside(_) { case (StatusCodes.OK, domain.OkResponse(_, _, StatusCodes.OK)) =>
|
||||
succeed
|
||||
})
|
||||
}): Future[Assertion]
|
||||
}
|
||||
}
|
||||
|
||||
@ -1287,19 +1217,19 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
"bazRecord": {"baz": "another baz value"}
|
||||
}
|
||||
}""")
|
||||
fixture.postJsonRequest(Uri.Path("/v1/create"), createCommand, headers).flatMap {
|
||||
case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
val contractId: ContractId = getContractId(getResult(output))
|
||||
fixture
|
||||
.postJsonRequest(Uri.Path("/v1/create"), createCommand, headers)
|
||||
.parseResponse[domain.ActiveContract[JsValue]]
|
||||
.flatMap(inside(_) { case (StatusCodes.OK, domain.OkResponse(c, _, StatusCodes.OK)) =>
|
||||
val contractId: ContractId = c.contractId
|
||||
|
||||
fixture.postJsonRequest(Uri.Path("/v1/fetch"), request, headers).flatMap {
|
||||
case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
activeContract(output).contractId shouldBe contractId
|
||||
}
|
||||
}: Future[Assertion]
|
||||
fixture
|
||||
.postJsonRequest(Uri.Path("/v1/fetch"), request, headers)
|
||||
.parseResponse[domain.ActiveContract[JsValue]]
|
||||
.flatMap(inside(_) { case (StatusCodes.OK, domain.OkResponse(c, _, StatusCodes.OK)) =>
|
||||
c.contractId shouldBe contractId
|
||||
})
|
||||
}): Future[Assertion]
|
||||
}
|
||||
|
||||
"query by a variant field" in withHttpService { fixture =>
|
||||
@ -1316,12 +1246,11 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
.map(_._1)
|
||||
.getOrElse(fail(s"Cannot retrieve packageId"))
|
||||
|
||||
postCreateCommand(command, fixture, headers).flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
val contractId: ContractId = getContractId(getResult(output))
|
||||
postCreateCommand(command, fixture, headers).flatMap(inside(_) {
|
||||
case (StatusCodes.OK, domain.OkResponse(result, _, StatusCodes.OK)) =>
|
||||
val contractId: ContractId = result.contractId
|
||||
|
||||
val query = jsObject(s"""{
|
||||
val query = jsObject(s"""{
|
||||
"templateIds": ["$packageId:Account:Account"],
|
||||
"query": {
|
||||
"number" : "abc123",
|
||||
@ -1329,15 +1258,14 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
}
|
||||
}""")
|
||||
|
||||
fixture.postJsonRequest(Uri.Path("/v1/query"), query, headers).map {
|
||||
case (searchStatus, searchOutput) =>
|
||||
searchStatus shouldBe StatusCodes.OK
|
||||
assertStatus(searchOutput, StatusCodes.OK)
|
||||
inside(activeContractList(searchOutput)) { case List(ac) =>
|
||||
ac.contractId shouldBe contractId
|
||||
}
|
||||
}
|
||||
}: Future[Assertion]
|
||||
fixture
|
||||
.postJsonRequest(Uri.Path("/v1/query"), query, headers)
|
||||
.parseResponse[List[domain.ActiveContract[JsValue]]]
|
||||
.map(inside(_) {
|
||||
case (StatusCodes.OK, domain.OkResponse(List(ac), _, StatusCodes.OK)) =>
|
||||
ac.contractId shouldBe contractId
|
||||
})
|
||||
}): Future[Assertion]
|
||||
}
|
||||
}
|
||||
|
||||
@ -1417,13 +1345,11 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
_ <- withHttpServiceOnly(ledgerPort) { innerFixture =>
|
||||
innerFixture
|
||||
.getRequest(Uri.Path("/v1/query"), headers)
|
||||
.flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
inside(getResult(output)) { case JsArray(result) =>
|
||||
.parseResponse[Vector[JsValue]]
|
||||
.map(inside(_) {
|
||||
case (StatusCodes.OK, domain.OkResponse(result, _, StatusCodes.OK)) =>
|
||||
result should have length 4
|
||||
}
|
||||
}: Future[Assertion]
|
||||
}): Future[Assertion]
|
||||
}
|
||||
} yield succeed
|
||||
}
|
||||
@ -1477,37 +1403,33 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
jsObject("""{"templateIds": ["Account:Account"]}"""),
|
||||
headers,
|
||||
)
|
||||
.flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
inside(getResult(output)) { case JsArray(result) =>
|
||||
result should have length n
|
||||
}
|
||||
}
|
||||
.parseResponse[Vector[JsValue]]
|
||||
.map(inside(_) { case (StatusCodes.OK, domain.OkResponse(result, _, StatusCodes.OK)) =>
|
||||
result should have length n
|
||||
})
|
||||
|
||||
for {
|
||||
resp <- fixture
|
||||
.postJsonRequest(Uri.Path("/v1/create-and-exercise"), encode(createCmd), headers)
|
||||
(status, output) = resp
|
||||
_ = {
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
.parseResponse[domain.ExerciseResponse[JsValue]]
|
||||
result = inside(resp) {
|
||||
case (StatusCodes.OK, domain.OkResponse(result, _, StatusCodes.OK)) =>
|
||||
result
|
||||
}
|
||||
created = getChild(getResult(output), "exerciseResult").convertTo[List[String]]
|
||||
created = result.exerciseResult.convertTo[List[String]]
|
||||
_ = created should have length numContracts
|
||||
|
||||
_ <- queryN(numContracts)
|
||||
|
||||
status <- fixture
|
||||
archiveResponse <- fixture
|
||||
.postJsonRequest(
|
||||
Uri.Path("/v1/create-and-exercise"),
|
||||
encode(archiveCmd(created)),
|
||||
headers,
|
||||
)
|
||||
.map(_._1)
|
||||
_ = {
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
.parseResponse[JsValue]
|
||||
_ = inside(archiveResponse) {
|
||||
case (StatusCodes.OK, domain.OkResponse(_, _, StatusCodes.OK)) =>
|
||||
}
|
||||
|
||||
_ <- queryN(0)
|
||||
@ -1565,11 +1487,9 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
.flatMap(headers =>
|
||||
fixture.postJsonRequest(Uri.Path("/v1/exercise"), exerciseJson, headers)
|
||||
)
|
||||
.map { case (exerciseStatus, exerciseOutput) =>
|
||||
exerciseStatus shouldBe StatusCodes.OK
|
||||
assertStatus(exerciseOutput, StatusCodes.OK)
|
||||
()
|
||||
}
|
||||
.parseResponse[JsValue]
|
||||
.map(inside(_) { case (StatusCodes.OK, domain.OkResponse(_, _, StatusCodes.OK)) =>
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
@ -1582,10 +1502,9 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
fixture
|
||||
.headersWithPartyAuth(actAs = List(fromPerspectiveOfParty.unwrap))
|
||||
.flatMap(headers => fixture.postJsonRequest(Uri.Path("/v1/query"), query, headers))
|
||||
.map { case (searchStatus, searchOutput) =>
|
||||
searchStatus shouldBe StatusCodes.OK
|
||||
assertStatus(searchOutput, StatusCodes.OK)
|
||||
}
|
||||
.parseResponse[JsValue]
|
||||
.map(inside(_) { case (StatusCodes.OK, domain.OkResponse(_, _, StatusCodes.OK)) =>
|
||||
})
|
||||
}
|
||||
|
||||
val commands = partyIds.map { p =>
|
||||
@ -1603,11 +1522,9 @@ abstract class AbstractHttpServiceIntegrationTestTokenIndependent
|
||||
headers,
|
||||
)
|
||||
)
|
||||
.map { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
getContractId(getResult(output))
|
||||
}: Future[ContractId]
|
||||
.map(inside(_) { case (StatusCodes.OK, domain.OkResponse(result, _, StatusCodes.OK)) =>
|
||||
result.contractId
|
||||
}): Future[ContractId]
|
||||
fut.map(cid => (party, cid))
|
||||
}
|
||||
(alice, aliceUserId) = users(0)
|
||||
|
@ -262,30 +262,43 @@ trait AbstractHttpServiceIntegrationTestFuns
|
||||
): Future[(StatusCode, domain.SyncResponse[Result])] =
|
||||
headersWithAuth
|
||||
.flatMap(postJsonRequest(path, json, _))
|
||||
.map(_ map (decode1[domain.SyncResponse, Result](_).fold(e => fail(e.shows), identity)))
|
||||
.parseResponse[Result]
|
||||
|
||||
def getRequest(path: Uri.Path, headers: List[HttpHeader]): Future[(StatusCode, JsValue)] =
|
||||
HttpServiceTestFixture.getRequest(uri withPath path, headers)
|
||||
def getRequest(
|
||||
path: Uri.Path,
|
||||
headers: List[HttpHeader],
|
||||
): Future[(StatusCode, JsValue)] =
|
||||
HttpServiceTestFixture
|
||||
.getRequest(uri withPath path, headers)
|
||||
|
||||
def getRequestWithMinimumAuth[Result: JsonReader](
|
||||
path: Uri.Path
|
||||
): Future[(StatusCode, domain.SyncResponse[Result])] =
|
||||
headersWithAuth
|
||||
.flatMap(getRequest(path, _))
|
||||
.map(_ map (decode1[domain.SyncResponse, Result](_).fold(e => fail(e.shows), identity)))
|
||||
.parseResponse[Result]
|
||||
}
|
||||
|
||||
implicit protected final class `Future JsValue functions`[A](
|
||||
private val self: Future[(A, JsValue)]
|
||||
) {
|
||||
def parseResponse[Result: JsonReader]: Future[(A, domain.SyncResponse[Result])] =
|
||||
self.map(_ map (decode1[domain.SyncResponse, Result](_).fold(e => fail(e.shows), identity)))
|
||||
}
|
||||
|
||||
protected def postCreateCommand(
|
||||
cmd: domain.CreateCommand[v.Record, OptionalPkg],
|
||||
fixture: UriFixture with EncoderFixture,
|
||||
headers: List[HttpHeader],
|
||||
): Future[(StatusCode, JsValue)] =
|
||||
HttpServiceTestFixture.postCreateCommand(cmd, fixture.encoder, fixture.uri, headers)
|
||||
): Future[(StatusCode, domain.SyncResponse[domain.ActiveContract[JsValue]])] =
|
||||
HttpServiceTestFixture
|
||||
.postCreateCommand(cmd, fixture.encoder, fixture.uri, headers)
|
||||
.parseResponse[domain.ActiveContract[JsValue]]
|
||||
|
||||
protected def postCreateCommand(
|
||||
cmd: domain.CreateCommand[v.Record, OptionalPkg],
|
||||
fixture: UriFixture with EncoderFixture,
|
||||
): Future[(StatusCode, JsValue)] =
|
||||
): Future[(StatusCode, domain.SyncResponse[domain.ActiveContract[JsValue]])] =
|
||||
fixture.headersWithAuth.flatMap(postCreateCommand(cmd, fixture, _))
|
||||
|
||||
protected def postArchiveCommand(
|
||||
@ -318,13 +331,11 @@ trait AbstractHttpServiceIntegrationTestFuns
|
||||
fixture: UriFixture with EncoderFixture,
|
||||
headers: List[HttpHeader],
|
||||
): Future[Assertion] =
|
||||
postContractsLookup(contractLocator, fixture.uri, headers).flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
val result = getResult(output)
|
||||
contractId shouldBe getContractId(result)
|
||||
assertActiveContract(result)(create, fixture.encoder)
|
||||
}
|
||||
postContractsLookup(contractLocator, fixture.uri, headers).map(inside(_) {
|
||||
case (StatusCodes.OK, domain.OkResponse(Some(resultContract), _, StatusCodes.OK)) =>
|
||||
contractId shouldBe resultContract.contractId
|
||||
assertActiveContract(resultContract)(create, fixture.encoder)
|
||||
})
|
||||
|
||||
protected def removeRecordId(a: v.Value): v.Value = a match {
|
||||
case v.Value(v.Value.Sum.Record(r)) if r.recordId.isDefined =>
|
||||
@ -506,33 +517,12 @@ trait AbstractHttpServiceIntegrationTestFuns
|
||||
)
|
||||
}
|
||||
|
||||
protected def result(jsObj: JsValue): JsValue = {
|
||||
inside(jsObj) { case JsObject(fields) =>
|
||||
inside(fields.get("result")) { case Some(value: JsValue) => value }
|
||||
}
|
||||
}
|
||||
|
||||
protected def assertStatus(jsObj: JsValue, expectedStatus: StatusCode): Assertion = {
|
||||
inside(jsObj) { case JsObject(fields) =>
|
||||
inside(fields.get("status")) { case Some(JsNumber(status)) =>
|
||||
status shouldBe BigDecimal(expectedStatus.intValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected def expectedOneErrorMessage(output: JsValue): String =
|
||||
inside(output) { case JsObject(fields) =>
|
||||
inside(fields.get("errors")) { case Some(JsArray(Vector(JsString(errorMsg)))) =>
|
||||
errorMsg
|
||||
}
|
||||
}
|
||||
|
||||
protected def postContractsLookup(
|
||||
cmd: domain.ContractLocator[JsValue],
|
||||
uri: Uri,
|
||||
headers: List[HttpHeader],
|
||||
readAs: Option[List[domain.Party]],
|
||||
): Future[(StatusCode, JsValue)] =
|
||||
): Future[(StatusCode, domain.SyncResponse[Option[domain.ActiveContract[JsValue]]])] =
|
||||
for {
|
||||
locjson <- toFuture(SprayJson.encode(cmd)): Future[JsValue]
|
||||
json <- toFuture(
|
||||
@ -545,27 +535,15 @@ trait AbstractHttpServiceIntegrationTestFuns
|
||||
)
|
||||
)
|
||||
result <- postJsonRequest(uri.withPath(Uri.Path("/v1/fetch")), json, headers)
|
||||
.parseResponse[Option[domain.ActiveContract[JsValue]]]
|
||||
} yield result
|
||||
|
||||
protected def postContractsLookup(
|
||||
cmd: domain.ContractLocator[JsValue],
|
||||
uri: Uri,
|
||||
headers: List[HttpHeader],
|
||||
): Future[(StatusCode, JsValue)] = postContractsLookup(cmd, uri, headers, None)
|
||||
|
||||
protected def activeContractList(output: JsValue): List[domain.ActiveContract[JsValue]] = {
|
||||
val result = getResult(output)
|
||||
SprayJson
|
||||
.decode[List[domain.ActiveContract[JsValue]]](result)
|
||||
.valueOr(e => fail(e.shows))
|
||||
}
|
||||
|
||||
protected def activeContract(output: JsValue): domain.ActiveContract[JsValue] = {
|
||||
val result = getResult(output)
|
||||
SprayJson
|
||||
.decode[domain.ActiveContract[JsValue]](result)
|
||||
.valueOr(e => fail(e.shows))
|
||||
}
|
||||
): Future[(StatusCode, domain.SyncResponse[Option[domain.ActiveContract[JsValue]]])] =
|
||||
postContractsLookup(cmd, uri, headers, None)
|
||||
|
||||
protected def asContractId(a: JsValue): domain.ContractId = inside(a) { case JsString(x) =>
|
||||
domain.ContractId(x)
|
||||
@ -640,11 +618,11 @@ trait AbstractHttpServiceIntegrationTestFuns
|
||||
}
|
||||
|
||||
protected def assertActiveContract(
|
||||
jsVal: JsValue
|
||||
activeContract: domain.ActiveContract[JsValue]
|
||||
)(
|
||||
command: domain.CreateCommand[v.Record, OptionalPkg],
|
||||
encoder: DomainJsonEncoder,
|
||||
): Future[Assertion] = {
|
||||
): Assertion = {
|
||||
|
||||
import encoder.implicits._
|
||||
|
||||
@ -653,11 +631,7 @@ trait AbstractHttpServiceIntegrationTestFuns
|
||||
.traversePayload(SprayJson.encode[v.Record](_))
|
||||
.getOrElse(fail(s"Failed to encode command: $command"))
|
||||
|
||||
Future {
|
||||
inside(SprayJson.decode[domain.ActiveContract[JsValue]](jsVal)) { case \/-(activeContract) =>
|
||||
(activeContract.payload: JsValue) shouldBe (expected.payload: JsValue)
|
||||
}
|
||||
}
|
||||
(activeContract.payload: JsValue) shouldBe (expected.payload: JsValue)
|
||||
}
|
||||
|
||||
protected def assertTemplateId(
|
||||
@ -695,7 +669,7 @@ trait AbstractHttpServiceIntegrationTestFuns
|
||||
serviceUri: Uri,
|
||||
party: domain.Party,
|
||||
headers: List[HttpHeader],
|
||||
): Future[(StatusCode, JsValue)] = {
|
||||
): Future[(StatusCode, domain.SyncResponse[domain.ActiveContract[JsValue]])] = {
|
||||
val partyJson = party.toJson.compactPrint
|
||||
val payload =
|
||||
s"""
|
||||
@ -710,18 +684,20 @@ trait AbstractHttpServiceIntegrationTestFuns
|
||||
| }
|
||||
|}
|
||||
|""".stripMargin
|
||||
HttpServiceTestFixture.postJsonStringRequest(
|
||||
serviceUri.withPath(Uri.Path("/v1/create")),
|
||||
payload,
|
||||
headers,
|
||||
)
|
||||
HttpServiceTestFixture
|
||||
.postJsonStringRequest(
|
||||
serviceUri.withPath(Uri.Path("/v1/create")),
|
||||
payload,
|
||||
headers,
|
||||
)
|
||||
.parseResponse[domain.ActiveContract[JsValue]]
|
||||
}
|
||||
|
||||
protected def initialAccountCreate(
|
||||
fixture: UriFixture with EncoderFixture,
|
||||
owner: domain.Party,
|
||||
headers: List[HttpHeader],
|
||||
): Future[(StatusCode, JsValue)] = {
|
||||
): Future[(StatusCode, domain.SyncResponse[domain.ActiveContract[JsValue]])] = {
|
||||
val command = accountCreateCommand(owner, "abc123")
|
||||
postCreateCommand(command, fixture, headers)
|
||||
}
|
||||
|
@ -11,14 +11,12 @@ import akka.http.scaladsl.model.ws.{
|
||||
TextMessage,
|
||||
WebSocketRequest,
|
||||
}
|
||||
import akka.http.scaladsl.model.{HttpHeader, StatusCodes, Uri}
|
||||
import akka.http.scaladsl.model.{HttpHeader, StatusCode, StatusCodes, Uri}
|
||||
import akka.stream.{KillSwitches, UniqueKillSwitch}
|
||||
import akka.stream.scaladsl.{Keep, Sink, Source}
|
||||
import com.daml.http.HttpServiceTestFixture.{
|
||||
UseTls,
|
||||
accountCreateCommand,
|
||||
getContractId,
|
||||
getResult,
|
||||
sharedAccountCreateCommand,
|
||||
}
|
||||
import com.daml.http.json.SprayJson
|
||||
@ -28,7 +26,6 @@ import org.scalatest._
|
||||
import org.scalatest.freespec.AsyncFreeSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import scalaz.std.option._
|
||||
import scalaz.std.tuple._
|
||||
import scalaz.std.vector._
|
||||
import scalaz.syntax.std.option._
|
||||
import scalaz.syntax.tag._
|
||||
@ -366,8 +363,9 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
aliceHeaders <- fixture.getUniquePartyAndAuthHeaders("Alice")
|
||||
(party, headers) = aliceHeaders
|
||||
creation <- initialIouCreate(uri, party, headers)
|
||||
_ = creation._1 shouldBe a[StatusCodes.Success]
|
||||
iouCid = getContractId(getResult(creation._2))
|
||||
iouCid = inside(creation) { case (_: StatusCodes.Success, domain.OkResponse(c, _, _)) =>
|
||||
c.contractId
|
||||
}
|
||||
jwt <- jwtForParties(uri)(List(party.unwrap), List(), testId)
|
||||
(kill, source) = singleClientQueryStream(jwt, uri, query)
|
||||
.viaMat(KillSwitches.single)(Keep.right)
|
||||
@ -475,8 +473,9 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
aliceHeaders <- getAliceHeaders
|
||||
(party, headers) = aliceHeaders
|
||||
creation <- initialIouCreate(uri, party, headers)
|
||||
_ = creation._1 shouldBe a[StatusCodes.Success]
|
||||
iouCid = getContractId(getResult(creation._2))
|
||||
iouCid = inside(creation) { case (_: StatusCodes.Success, domain.OkResponse(c, _, _)) =>
|
||||
c.contractId
|
||||
}
|
||||
jwt <- jwtForParties(uri)(List(party.unwrap), List(), testId)
|
||||
(kill, source) = singleClientQueryStream(jwt, uri, query)
|
||||
.viaMat(KillSwitches.single)(Keep.right)
|
||||
@ -494,6 +493,13 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
}
|
||||
}
|
||||
|
||||
private[this] def resultContractId(
|
||||
r: (StatusCode, domain.SyncResponse[domain.ActiveContract[_]])
|
||||
) =
|
||||
inside(r) { case (_: StatusCodes.Success, domain.OkResponse(result, _, _)) =>
|
||||
result.contractId
|
||||
}
|
||||
|
||||
"multi-party query should receive deltas as contracts are archived/created" in withHttpService {
|
||||
fixture =>
|
||||
import fixture.uri
|
||||
@ -576,12 +582,10 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
}
|
||||
|
||||
r1 <- f1
|
||||
_ = r1._1 shouldBe a[StatusCodes.Success]
|
||||
cid1 = getContractId(getResult(r1._2))
|
||||
cid1 = resultContractId(r1)
|
||||
|
||||
r2 <- f2
|
||||
_ = r2._1 shouldBe a[StatusCodes.Success]
|
||||
cid2 = getContractId(getResult(r2._2))
|
||||
cid2 = resultContractId(r2)
|
||||
|
||||
jwt <- jwtForParties(uri)(List(alice.unwrap, bob.unwrap), List(), testId)
|
||||
(kill, source) = singleClientQueryStream(
|
||||
@ -685,12 +689,10 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
)
|
||||
}
|
||||
r1 <- f1
|
||||
_ = r1._1 shouldBe a[StatusCodes.Success]
|
||||
cid1 = getContractId(getResult(r1._2))
|
||||
cid1 = resultContractId(r1)
|
||||
|
||||
r2 <- f2
|
||||
_ = r2._1 shouldBe a[StatusCodes.Success]
|
||||
cid2 = getContractId(getResult(r2._2))
|
||||
cid2 = resultContractId(r2)
|
||||
jwt <- jwtForParties(uri)(List(alice.unwrap), List(), testId)
|
||||
(kill, source) = singleClientFetchStream(jwt, uri, fetchRequest(None))
|
||||
.viaMat(KillSwitches.single)(Keep.right)
|
||||
@ -738,10 +740,7 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
fixture,
|
||||
headers,
|
||||
)
|
||||
} yield {
|
||||
assert(r._1.isSuccess)
|
||||
getContractId(getResult(r._2))
|
||||
}
|
||||
} yield resultContractId(r)
|
||||
archive = (id: domain.ContractId) =>
|
||||
for {
|
||||
r <- postArchiveCommand(
|
||||
@ -864,12 +863,10 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
)
|
||||
}
|
||||
r1 <- f1
|
||||
_ = r1._1 shouldBe a[StatusCodes.Success]
|
||||
cid1 = getContractId(getResult(r1._2))
|
||||
cid1 = resultContractId(r1)
|
||||
|
||||
r2 <- f2
|
||||
_ = r2._1 shouldBe a[StatusCodes.Success]
|
||||
cid2 = getContractId(getResult(r2._2))
|
||||
cid2 = resultContractId(r2)
|
||||
|
||||
jwt <- jwtForParties(uri)(List(alice.unwrap, bob.unwrap), List(), testId)
|
||||
(kill, source) = singleClientFetchStream(
|
||||
@ -999,7 +996,7 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
fixture: UriFixture with EncoderFixture,
|
||||
headers: List[HttpHeader],
|
||||
): Future[(domain.Offset, domain.Offset)] = {
|
||||
import json.JsonProtocol._, fixture.uri
|
||||
import fixture.uri
|
||||
type In = JsValue // JsValue might not be the most convenient choice
|
||||
val syntax = Consume.syntax[In]
|
||||
import syntax._
|
||||
@ -1013,10 +1010,9 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
headers,
|
||||
)
|
||||
)
|
||||
cid = inside(
|
||||
create map (_.convertTo[domain.SyncResponse[domain.ActiveContract[JsValue]]])
|
||||
) { case (StatusCodes.OK, domain.OkResponse(contract, _, StatusCodes.OK)) =>
|
||||
contract.contractId
|
||||
cid = inside(create) {
|
||||
case (StatusCodes.OK, domain.OkResponse(contract, _, StatusCodes.OK)) =>
|
||||
contract.contractId
|
||||
}
|
||||
// wait for the creation's offset
|
||||
offsetAfter <- readUntil[In] {
|
||||
@ -1205,7 +1201,7 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
for {
|
||||
jwtForAliceAndBob <-
|
||||
jwtForParties(uri)(actAs = aliceAndBob, readAs = Nil, ledgerId = testId)
|
||||
(status, value) <-
|
||||
createResponse <-
|
||||
fixture
|
||||
.headersWithPartyAuth(aliceAndBob)
|
||||
.flatMap(headers =>
|
||||
@ -1215,8 +1211,7 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
headers = headers,
|
||||
)
|
||||
)
|
||||
_ = status shouldBe a[StatusCodes.Success]
|
||||
expectedContractId = getContractId(getResult(value))
|
||||
expectedContractId = resultContractId(createResponse)
|
||||
(killSwitch, source) = singleClientQueryStream(
|
||||
jwt = jwtForAliceAndBob,
|
||||
serviceUri = uri,
|
||||
|
@ -5,7 +5,7 @@
|
||||
- Updating the package service succeeds with sufficient authorization: [AuthorizationTest.scala](ledger-service/http-json/src/it/scala/http/AuthorizationTest.scala#L89)
|
||||
- accept user tokens: [TestMiddleware.scala](triggers/service/auth/src/test/scala/com/daml/auth/middleware/oauth2/TestMiddleware.scala#L152)
|
||||
- badly-authorized create is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L60)
|
||||
- badly-authorized create is rejected: [AbstractHttpServiceIntegrationTest.scala](ledger-service/http-json/src/itlib/scala/http/AbstractHttpServiceIntegrationTest.scala#L1086)
|
||||
- badly-authorized create is rejected: [AbstractHttpServiceIntegrationTest.scala](ledger-service/http-json/src/itlib/scala/http/AbstractHttpServiceIntegrationTest.scala#L1029)
|
||||
- badly-authorized exercise is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L158)
|
||||
- badly-authorized exercise/create (create is unauthorized) is rejected: [AuthPropagationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthPropagationSpec.scala#L275)
|
||||
- badly-authorized exercise/create (exercise is unauthorized) is rejected: [AuthPropagationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthPropagationSpec.scala#L243)
|
||||
@ -13,20 +13,20 @@
|
||||
- badly-authorized fetch is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L95)
|
||||
- badly-authorized lookup is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L117)
|
||||
- create IOU should fail if overwritten actAs & readAs result in missing permission even if the user would have the rights: [HttpServiceIntegrationTestUserManagement.scala](ledger-service/http-json/src/it/scala/http/HttpServiceIntegrationTestUserManagement.scala#L134)
|
||||
- create IOU should fail if user has no permission: [HttpServiceIntegrationTestUserManagement.scala](ledger-service/http-json/src/it/scala/http/HttpServiceIntegrationTestUserManagement.scala#L108)
|
||||
- create IOU should fail if user has no permission: [HttpServiceIntegrationTestUserManagement.scala](ledger-service/http-json/src/it/scala/http/HttpServiceIntegrationTestUserManagement.scala#L107)
|
||||
- create IOU should work with correct user rights: [HttpServiceIntegrationTestUserManagement.scala](ledger-service/http-json/src/it/scala/http/HttpServiceIntegrationTestUserManagement.scala#L81)
|
||||
- create with no signatories is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L50)
|
||||
- create with non-signatory maintainers is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L72)
|
||||
- exercise with no controllers is rejected: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L148)
|
||||
- fetch fails when readAs not authed, even if prior fetch succeeded: [AbstractHttpServiceIntegrationTest.scala](ledger-service/http-json/src/itlib/scala/http/AbstractHttpServiceIntegrationTest.scala#L1146)
|
||||
- fetch fails when readAs not authed, even if prior fetch succeeded: [AbstractHttpServiceIntegrationTest.scala](ledger-service/http-json/src/itlib/scala/http/AbstractHttpServiceIntegrationTest.scala#L1083)
|
||||
- forbid a non-authorized party to check the status of a trigger: [TriggerServiceTest.scala](triggers/service/src/test/scala/com/digitalasset/daml/lf/engine/trigger/TriggerServiceTest.scala#L669)
|
||||
- forbid a non-authorized party to list triggers: [TriggerServiceTest.scala](triggers/service/src/test/scala/com/digitalasset/daml/lf/engine/trigger/TriggerServiceTest.scala#L659)
|
||||
- forbid a non-authorized party to start a trigger: [TriggerServiceTest.scala](triggers/service/src/test/scala/com/digitalasset/daml/lf/engine/trigger/TriggerServiceTest.scala#L648)
|
||||
- forbid a non-authorized party to stop a trigger: [TriggerServiceTest.scala](triggers/service/src/test/scala/com/digitalasset/daml/lf/engine/trigger/TriggerServiceTest.scala#L685)
|
||||
- forbid a non-authorized user to upload a DAR: [TriggerServiceTest.scala](triggers/service/src/test/scala/com/digitalasset/daml/lf/engine/trigger/TriggerServiceTest.scala#L701)
|
||||
- multiple websocket requests over the same WebSocket connection are NOT allowed: [AbstractWebsocketServiceIntegrationTest.scala](ledger-service/http-json/src/itlib/scala/http/AbstractWebsocketServiceIntegrationTest.scala#L118)
|
||||
- multiple websocket requests over the same WebSocket connection are NOT allowed: [AbstractWebsocketServiceIntegrationTest.scala](ledger-service/http-json/src/itlib/scala/http/AbstractWebsocketServiceIntegrationTest.scala#L115)
|
||||
- refresh a token after expiry on the server side: [TriggerServiceTest.scala](triggers/service/src/test/scala/com/digitalasset/daml/lf/engine/trigger/TriggerServiceTest.scala#L726)
|
||||
- reject requests with missing auth header: [AbstractHttpServiceIntegrationTest.scala](ledger-service/http-json/src/itlib/scala/http/AbstractHttpServiceIntegrationTest.scala#L543)
|
||||
- reject requests with missing auth header: [AbstractHttpServiceIntegrationTest.scala](ledger-service/http-json/src/itlib/scala/http/AbstractHttpServiceIntegrationTest.scala#L520)
|
||||
- request a fresh token after expiry on user request: [TriggerServiceTest.scala](triggers/service/src/test/scala/com/digitalasset/daml/lf/engine/trigger/TriggerServiceTest.scala#L711)
|
||||
- return the token from a cookie: [TestMiddleware.scala](triggers/service/auth/src/test/scala/com/daml/auth/middleware/oauth2/TestMiddleware.scala#L96)
|
||||
- return unauthorized on an expired token: [TestMiddleware.scala](triggers/service/auth/src/test/scala/com/daml/auth/middleware/oauth2/TestMiddleware.scala#L139)
|
||||
@ -35,9 +35,9 @@
|
||||
- return unauthorized without cookie: [TestMiddleware.scala](triggers/service/auth/src/test/scala/com/daml/auth/middleware/oauth2/TestMiddleware.scala#L87)
|
||||
- the /login endpoint with an oauth server checking claims should not authorize disallowed admin claims: [TestMiddleware.scala](triggers/service/auth/src/test/scala/com/daml/auth/middleware/oauth2/TestMiddleware.scala#L343)
|
||||
- the /login endpoint with an oauth server checking claims should not authorize unauthorized parties: [TestMiddleware.scala](triggers/service/auth/src/test/scala/com/daml/auth/middleware/oauth2/TestMiddleware.scala#L336)
|
||||
- websocket request with invalid protocol token should be denied: [AbstractWebsocketServiceIntegrationTest.scala](ledger-service/http-json/src/itlib/scala/http/AbstractWebsocketServiceIntegrationTest.scala#L98)
|
||||
- websocket request with valid protocol token should allow client subscribe to stream: [AbstractWebsocketServiceIntegrationTest.scala](ledger-service/http-json/src/itlib/scala/http/AbstractWebsocketServiceIntegrationTest.scala#L86)
|
||||
- websocket request without protocol token should be denied: [AbstractWebsocketServiceIntegrationTest.scala](ledger-service/http-json/src/itlib/scala/http/AbstractWebsocketServiceIntegrationTest.scala#L108)
|
||||
- websocket request with invalid protocol token should be denied: [AbstractWebsocketServiceIntegrationTest.scala](ledger-service/http-json/src/itlib/scala/http/AbstractWebsocketServiceIntegrationTest.scala#L95)
|
||||
- websocket request with valid protocol token should allow client subscribe to stream: [AbstractWebsocketServiceIntegrationTest.scala](ledger-service/http-json/src/itlib/scala/http/AbstractWebsocketServiceIntegrationTest.scala#L83)
|
||||
- websocket request without protocol token should be denied: [AbstractWebsocketServiceIntegrationTest.scala](ledger-service/http-json/src/itlib/scala/http/AbstractWebsocketServiceIntegrationTest.scala#L105)
|
||||
- well-authorized create is accepted: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L43)
|
||||
- well-authorized exercise is accepted: [AuthorizationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthorizationSpec.scala#L141)
|
||||
- well-authorized exercise/create is accepted: [AuthPropagationSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/AuthPropagationSpec.scala#L221)
|
||||
@ -180,7 +180,7 @@
|
||||
- contract keys should be evaluated after ensure clause: [ContractKeySpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/ContractKeySpec.scala#L188)
|
||||
- contract keys should be evaluated only when executing create: [ContractKeySpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/ContractKeySpec.scala#L149)
|
||||
- exercise_interface with a contract instance that does not implement the interface fails.: [EvaluationOrderTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/EvaluationOrderTest.scala#L1615)
|
||||
- fromStartupMode should not succeed for any input when the db connection is broken: [FailureTests.scala](ledger-service/http-json/src/failurelib/scala/http/FailureTests.scala#L421)
|
||||
- fromStartupMode should not succeed for any input when the db connection is broken: [FailureTests.scala](ledger-service/http-json/src/failurelib/scala/http/FailureTests.scala#L436)
|
||||
- redirect to the configured callback URI after login: [TriggerServiceTest.scala](triggers/service/src/test/scala/com/digitalasset/daml/lf/engine/trigger/TriggerServiceTest.scala#L630)
|
||||
- restart trigger on initialization failure due to failed connection: [TriggerServiceTest.scala](triggers/service/src/test/scala/com/digitalasset/daml/lf/engine/trigger/TriggerServiceTest.scala#L446)
|
||||
- restart trigger on run-time failure due to dropped connection: [TriggerServiceTest.scala](triggers/service/src/test/scala/com/digitalasset/daml/lf/engine/trigger/TriggerServiceTest.scala#L466)
|
||||
@ -202,8 +202,8 @@
|
||||
|
||||
## Performance:
|
||||
- Tail call optimization: Tail recursion does not blow the scala JVM stack.: [TailCallTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/TailCallTest.scala#L16)
|
||||
- archiving a large number of contracts should succeed: [AbstractHttpServiceIntegrationTest.scala](ledger-service/http-json/src/itlib/scala/http/AbstractHttpServiceIntegrationTest.scala#L1432)
|
||||
- creating and listing 20K users should be possible: [HttpServiceIntegrationTestUserManagement.scala](ledger-service/http-json/src/it/scala/http/HttpServiceIntegrationTestUserManagement.scala#L565)
|
||||
- archiving a large number of contracts should succeed: [AbstractHttpServiceIntegrationTest.scala](ledger-service/http-json/src/itlib/scala/http/AbstractHttpServiceIntegrationTest.scala#L1358)
|
||||
- creating and listing 20K users should be possible: [HttpServiceIntegrationTestUserManagement.scala](ledger-service/http-json/src/it/scala/http/HttpServiceIntegrationTestUserManagement.scala#L557)
|
||||
|
||||
## Input Validation:
|
||||
- TLS configuration is parsed correctly from the config file: [CliSpec.scala](ledger-service/http-json/src/test/scala/com/digitalasset/http/CliSpec.scala#L273)
|
||||
|
Loading…
Reference in New Issue
Block a user