Check trigger dao migrations digests (#7908)

* Check the trigger dao migrations digest

Following the example of the corresponding ledger on SQL tests.

The digests had to be updated as both of them had gone out of sync.
The init digest presumably due to the change in #7226 and the one for
adding the access token during review of #7890.

changelog_begin
changelog_end

* define abstract migrations test

* Use abstract migrations test in trigger service tests

* use abstract migrations test in ledger on SQL

* Retain check for number of .sql resources

* Factor out the hash-migrations script

* Consistent shell settings

Addressing review comment

Co-authored-by: Andreas Herrmann <andreas.herrmann@tweag.io>
This commit is contained in:
Andreas Herrmann 2020-11-06 10:20:32 +01:00 committed by GitHub
parent 08e1dc34ef
commit 9758b2f85b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 140 additions and 78 deletions

View File

@ -216,6 +216,7 @@ da_scala_test_suite(
"//ledger/participant-state/kvutils",
"//ledger/participant-state/kvutils:kvutils-tests-lib",
"//libs-scala/contextualized-logging",
"//libs-scala/flyway-testing",
"//libs-scala/postgresql-testing",
"//libs-scala/resources",
"@maven//:com_typesafe_akka_akka_actor_2_12",

View File

@ -3,11 +3,10 @@
# Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
set -e
set -u
set -eou pipefail
shopt -s globstar
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
for file in "$DIR"/src/main/resources/com/daml/ledger/on/sql/migrations/**/*.sql; do
shasum -a 256 "$file" | awk '{ print $1 }' > "$file.sha256"
done
"$DIR"/../../libs-scala/flyway-testing/hash-migrations.sh \
"$DIR"/src/main/resources/com/daml/ledger/on/sql/migrations/**/*.sql

View File

@ -3,76 +3,10 @@
package com.daml.ledger.on.sql
import java.io.{BufferedReader, FileNotFoundException}
import java.math.BigInteger
import java.nio.charset.Charset
import java.security.MessageDigest
import java.util
import com.daml.flyway.AbstractImmutableMigrationsSpec
import com.daml.ledger.on.sql.ImmutableMigrationsSpec._
import org.flywaydb.core.Flyway
import org.flywaydb.core.api.configuration.FluentConfiguration
import org.flywaydb.core.internal.resource.LoadableResource
import org.flywaydb.core.internal.scanner.{LocationScannerCache, ResourceNameCache, Scanner}
import org.scalatest.Matchers._
import org.scalatest.WordSpec
import scala.collection.JavaConverters._
class ImmutableMigrationsSpec extends WordSpec {
"migration files" should {
"never change, according to their accompanying digest file" in {
val configuration = Flyway
.configure()
.locations(s"classpath:/$migrationsResourcePath")
val resourceScanner = flywayScanner(configuration)
val resources = resourceScanner.getResources("", ".sql").asScala.toSeq
resources.size should be >= 3
resources.foreach { resource =>
val migrationFile = resource.getRelativePath
val digestFile = migrationFile + ".sha256"
val expectedDigest = readExpectedDigest(digestFile, resourceScanner)
val currentDigest = computeCurrentDigest(resource, configuration.getEncoding)
assert(
currentDigest == expectedDigest,
s"""The contents of the migration file "$migrationFile" have changed! Migrations are immutable; you must not change their contents or their digest.""",
)
}
}
}
}
object ImmutableMigrationsSpec {
private val migrationsResourcePath = "com/daml/ledger/on/sql/migrations"
private val hashMigrationsScriptPath = "ledger/ledger-on-sql/hash-migrations.sh"
private def flywayScanner(configuration: FluentConfiguration) =
new Scanner(
classOf[Object],
util.Arrays.asList(configuration.getLocations: _*),
getClass.getClassLoader,
configuration.getEncoding,
new ResourceNameCache,
new LocationScannerCache,
)
private def readExpectedDigest(
digestFile: String,
resourceScanner: Scanner[_],
): String = {
val resource = Option(resourceScanner.getResource(digestFile))
.getOrElse(throw new FileNotFoundException(
s"""\"$digestFile\" is missing. If you are introducing a new Flyway migration step, you need to create an SHA-256 digest file by running $hashMigrationsScriptPath."""))
new BufferedReader(resource.read()).readLine()
}
private def computeCurrentDigest(resource: LoadableResource, encoding: Charset): String = {
val sha256 = MessageDigest.getInstance("SHA-256")
new BufferedReader(resource.read())
.lines()
.forEach(line => sha256.update((line + "\n").getBytes(encoding)))
val digest = sha256.digest()
String.format(s"%0${digest.length * 2}x", new BigInteger(1, digest))
}
class ImmutableMigrationsSpec extends AbstractImmutableMigrationsSpec {
protected override val migrationsResourcePath = "com/daml/ledger/on/sql/migrations"
protected override val migrationsMinSize = 3
protected override val hashMigrationsScriptPath = "ledger/ledger-on-sql/hash-migrations.sh"
}

View File

@ -0,0 +1,16 @@
# Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
load("//bazel_tools:scala.bzl", "da_scala_library")
da_scala_library(
name = "flyway-testing",
srcs = glob(["src/main/scala/**/*.scala"]),
tags = ["maven_coordinates=com.daml:flyway-testing:__VERSION__"],
visibility = ["//visibility:public"],
deps = [
"@maven//:org_flywaydb_flyway_core",
"@maven//:org_scalactic_scalactic_2_12",
"@maven//:org_scalatest_scalatest_2_12",
],
)

View File

@ -0,0 +1,10 @@
#!/usr/bin/env bash
# Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
set -eou pipefail
for file in "$@"; do
shasum -a 256 "$file" | awk '{ print $1 }' > "$file.sha256"
done

View File

@ -0,0 +1,76 @@
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package com.daml.flyway
import java.io.{BufferedReader, FileNotFoundException}
import java.math.BigInteger
import java.nio.charset.Charset
import java.security.MessageDigest
import java.util
import org.flywaydb.core.Flyway
import org.flywaydb.core.api.configuration.FluentConfiguration
import org.flywaydb.core.internal.resource.LoadableResource
import org.flywaydb.core.internal.scanner.{LocationScannerCache, ResourceNameCache, Scanner}
import org.scalatest.Matchers._
import org.scalatest.WordSpec
import scala.collection.JavaConverters._
abstract class AbstractImmutableMigrationsSpec extends WordSpec {
protected def migrationsResourcePath: String
protected def migrationsMinSize: Int
protected def hashMigrationsScriptPath: String
private def flywayScanner(configuration: FluentConfiguration) =
new Scanner(
classOf[Object],
util.Arrays.asList(configuration.getLocations: _*),
getClass.getClassLoader,
configuration.getEncoding,
new ResourceNameCache,
new LocationScannerCache,
)
private def readExpectedDigest(
digestFile: String,
resourceScanner: Scanner[_],
): String = {
val resource = Option(resourceScanner.getResource(digestFile))
.getOrElse(throw new FileNotFoundException(
s"""\"$digestFile\" is missing. If you are introducing a new Flyway migration step, you need to create an SHA-256 digest file by running $hashMigrationsScriptPath."""))
new BufferedReader(resource.read()).readLine()
}
private def computeCurrentDigest(resource: LoadableResource, encoding: Charset): String = {
val sha256 = MessageDigest.getInstance("SHA-256")
new BufferedReader(resource.read())
.lines()
.forEach(line => sha256.update((line + "\n").getBytes(encoding)))
val digest = sha256.digest()
String.format(s"%0${digest.length * 2}x", new BigInteger(1, digest))
}
"migration files" should {
"never change, according to their accompanying digest file" in {
val configuration = Flyway
.configure()
.locations(s"classpath:/$migrationsResourcePath")
val resourceScanner = flywayScanner(configuration)
val resources = resourceScanner.getResources("", ".sql").asScala.toSeq
resources.size should be >= migrationsMinSize
resources.foreach { resource =>
val migrationFile = resource.getRelativePath
val digestFile = migrationFile + ".sha256"
val expectedDigest = readExpectedDigest(digestFile, resourceScanner)
val currentDigest = computeCurrentDigest(resource, configuration.getEncoding)
assert(
currentDigest == expectedDigest,
s"""The contents of the migration file "$migrationFile" have changed! Migrations are immutable; you must not change their contents or their digest.""",
)
}
}
}
}

View File

@ -115,6 +115,7 @@ da_scala_test(
"//ledger/participant-state",
"//ledger/sandbox-classic",
"//ledger/sandbox-common",
"//libs-scala/flyway-testing",
"//libs-scala/ports",
"//libs-scala/postgresql-testing",
"//libs-scala/resources",
@ -127,6 +128,7 @@ da_scala_test(
"@maven//:com_typesafe_akka_akka_parsing_2_12",
"@maven//:eu_rekawek_toxiproxy_toxiproxy_java_2_1_3",
"@maven//:io_spray_spray_json_2_12",
"@maven//:org_flywaydb_flyway_core",
"@maven//:org_scalatest_scalatest_2_12",
"@maven//:org_scalaz_scalaz_core_2_12",
],

View File

@ -0,0 +1,12 @@
#!/usr/bin/env bash
# Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
set -eou pipefail
shopt -s globstar
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
"$DIR"/../../libs-scala/flyway-testing/hash-migrations.sh \
"$DIR"/src/main/resources/com/daml/lf/engine/trigger/db/migration/**/*.sql

View File

@ -1 +0,0 @@
cbac336e1d253707f6ef4dd866b7ed107be3dd908906c446202f5dc7f8594c48

View File

@ -0,0 +1 @@
9e3bad4ec8947cea838aaabaffeaa81c0084fffd3f1f930caa9d43309c9bb7fa

View File

@ -1 +0,0 @@
6762d275f249330869111253545121673c09faf31fb032b78654106380d167fa

View File

@ -0,0 +1 @@
774600d1fcdab326edc840421da21d42ed2022d15fdbdb10e319364a2a1de7ba

View File

@ -0,0 +1,12 @@
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package com.daml.lf.engine.trigger
import com.daml.flyway.AbstractImmutableMigrationsSpec
class ImmutableMigrationsSpec extends AbstractImmutableMigrationsSpec {
protected override val migrationsResourcePath = "com/daml/lf/engine/trigger/db/migration/postgres"
protected override val migrationsMinSize = 2
protected override val hashMigrationsScriptPath = "trigger/service/hash-migrations.sh"
}