daml/ledger/ledger-api-integration-tests
Samir Talwar 0ff716df2a Ledger API: Add healthcheck endpoints. (#3573)
* grpc-definitions: Delete health_service.proto

We can use the version in io.grpc:grpc-services instead.

* ledger: Delete ledger/API.md.

* sandbox: Fix warnings in ApiServices flagged by IntelliJ.

* sandbox: Implement a dummy grpc.health.v1.Health.Check endpoint.

* sandbox: Implement a dummy grpc.health.v1.Health.Watch endpoint.

* sandbox: Drop repeated elements from grpc.health.v1.Health.Watch.

* sandbox: Wrap the HealthService in basic tests.

* sandbox: Stop streaming the server health too.

* ledger-api-test-tool: Health check tests.

* Add a changelog entry for the health check endpoints.

CHANGELOG_BEGIN

- [Ledger API] Add healthcheck endpoints, conforming to the
  `GRPC Health Checking Protocol <https://github.com/grpc/grpc/blob/master/doc/health-checking.md>`_.
  It is always ``SERVING`` for now.

- [DAML Ledger Integration Kit] Add conformance test coverage for the
  ``grpc.health.v1.Health`` service.

CHANGELOG_END

* ledger-api-integration-tests: Increment the number of services.

* Apply suggestions from code review

Co-Authored-By: Stefano Baghino <43749967+stefanobaghino-da@users.noreply.github.com>

* sandbox: Use `AkkaBeforeAndAfterAll` in the HealthServiceSpec.

In an attempt to get it working on CI.

* sandbox: Change `dropRepeated` to `DropRepeated()`.

Keep it in one file.

* test-common: Use `Delayed.by` in `TimeBoundObserver`.

* test-common: Close the source when `TimeBoundObserver` completes.

* ./fmt.sh

That'll teach me not to `--no-verify` just because it's a merge commit.

* sandbox: Inline `HealthService.suppress`.

At some point it was being used twice.

* sandbox: Increase the timeout for HealthServiceSpec.

* sandbox: Reimplement HealthService using the Scala protobuf types.

* sandbox: Generate an Akka-compatible trait for the health service.

And refactor a lot of test code to make it easy to test.

* ledger-api-common: Move the HealthService here.

* rs-grpc-testing-utils: Publish to Maven.

* rs-grpc-testing-utils: Add Maven coordinates.
2019-11-22 14:02:05 +00:00
..
src/test Ledger API: Add healthcheck endpoints. (#3573) 2019-11-22 14:02:05 +00:00
BUILD.bazel Extractor with authentication (#3514) 2019-11-19 17:12:25 +01:00
README.md Add notes on writing tests (#2264) 2019-07-24 07:28:50 +02:00

Integration tests for Ledger API based implementations

This module contains various integration tests running against Ledger API implementations (sandbox, platform).

Due to the time and resource requirements of these tests, they don't run by the normal test task of the build. Instead the test jar and its dependencies are packaged into a .tgz archive, which can be started using java -jar ledger-api-integration-tests.jar, using scalatest Runner arguments (see http://www.scalatest.org/user_guide/using_the_runner ). This .tgz is stashed during the normal build, and used later in several, concurrently run Jenkins stages.

Scenario based semantic tests

The scenario based semantic tests are running scenarios found in DAML libraries against the sandbox and the platform.

Testing behavior for scenario based semantic tests. The usage pattern is as follows:

class SomeTest extends AsyncFlatSpec
  with TestExecutionSequencerFactory
  with AkkaBeforeAndAfterAll
  with SemanticTestBehavior {

val scenariosToExclude = Map(LedgerBackend.Sandbox => (scenarioName) => true,
                             LedgerBackend.Platform => Set("Test.scenario"))

config(ModuleId("<groupId>", "<artifactId>", "<version>", "dar"), "committer", scenariosToExclude)
  .run
  .unsafePerformSync
  .fold(e => sys.error(s"$e"), identity)
  .toConfigurationVector(Set(LedgerBackend.Platform))
  .foreach(semanticTestBehavior)
}

Since dynamic runtime configuration of scalatest tests are a bit messy, the configuration is static for each test suite. Although multiple configurations can be executed in each suite, a Jenkins stage can only run one or more test suites. It is not possible to run only parts of a suite. That is why there are two suite classes, one for sandbox and one for platform for each DAML library.

The config function returns a scalaz.concurrent.Task, which loads the configuration. The implementation loads the DAML package, discovers all the scenarios, including the necessary stakeholders for each scenario, inspects which scenarios are manipulating time, and based on these data creates a configuration.

After running the task, the toConfigurationVector creates a list of configuration vectors. Each element in this list represents one run of either sandbox or platform, for a given participant configuration, and a list of scenarios to execute.

For every element of this list one should call semanticTestBehavior, which starts the configured backend, set up with the configured participants, and executes the configured scenarios (to be precise, the SemanticTester creates a list of commands and expected responses based on the content of the scenarios, and executes these commands on the backend).

Writing integration tests

The integration tests should work with any conformant DAML ledger. This includes not only our sandbox, but also other ledger implementations.

The following are important considerations for writing integration tests.

Exclusive access

Don't assume you have exclusive access to the ledger. Other tests or applications may be running concurrently.

  • Don't make assumptions on how ledger offsets evolve. Other applications may modify the ledger in between your commands.
  • Make sure command and workflow IDs are globally unique, and not shared between test runs.
    • See TestIdsGenerator.testCommandId and TestIdsGenerator.testWorkflowId
  • Make sure party names are globally unique, and not shared between test runs.
    • See TestIdsGenerator.testPartyName
  • Thanks to our privacy model, using unique party names and workflow IDs will essentially create a private sub-ledger and make sure none of your actions interfere with the rest of the ledger.

Previous ledger content

Don't make assumptions on the previous content of the ledger. The ledger may be completely empty, or it may be a long running ledger with millions of ledger entries.

  • Don't start streaming from genesis. Instead, at the start of the test, read the ledger begin, and start all streaming from there.
  • Make sure all required DAML packages are uploaded and all required parties are allocated before the test runs. Note that the packages may or may not have been previously uploaded by other applications.
    • If possible, upload packages and allocate parties at the beginning of the test using the admin API. In the future, this setup step will be handled by the test tool itself.
  • Be mindful when using commands that return unfiltered results. For example, ListKnownPartiesRequest could return a huge number of entries.