Skip to content

Commit ea42321

Browse files
authored
ENT-5759 check for app schema migration (corda#6701)
* Fix behaviour for missing schema outside devMode plus test
1 parent 7ec59da commit ea42321

File tree

8 files changed

+104
-3
lines changed

8 files changed

+104
-3
lines changed

node/build.gradle

+2
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,8 @@ dependencies {
242242
slowIntegrationTestRuntime configurations.runtime
243243
slowIntegrationTestRuntime configurations.testRuntime
244244

245+
integrationTestCompile(project(":testing:cordapps:missingmigration"))
246+
245247
testCompile project(':testing:cordapps:dbfailure:dbfworkflows')
246248
}
247249

node/src/integration-test/kotlin/net/corda/node/persistence/DbSchemaInitialisationTest.kt

+29
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,16 @@ package net.corda.node.persistence
33
import net.corda.core.utilities.getOrThrow
44
import net.corda.node.flows.isQuasarAgentSpecified
55
import net.corda.node.internal.ConfigurationException
6+
import net.corda.nodeapi.internal.persistence.CouldNotCreateDataSourceException
7+
import net.corda.nodeapi.internal.persistence.HibernateSchemaChangeException
8+
import net.corda.testing.core.ALICE_NAME
69
import net.corda.testing.driver.DriverParameters
710
import net.corda.testing.driver.NodeParameters
811
import net.corda.testing.driver.driver
12+
import net.corda.testing.node.TestCordapp
913
import org.junit.Test
14+
import net.corda.testing.node.internal.startNode
15+
import org.assertj.core.api.Assertions.assertThatExceptionOfType
1016
import kotlin.test.assertFailsWith
1117

1218
class DbSchemaInitialisationTest {
@@ -19,4 +25,27 @@ class DbSchemaInitialisationTest {
1925
}
2026
}
2127

28+
@Test(timeout = 300_000)
29+
fun `app migration resource is only mandatory when not in dev mode`() {
30+
driver(DriverParameters(startNodesInProcess = true,
31+
cordappsForAllNodes = emptyList(),
32+
allowHibernateToManageAppSchema = false)) {
33+
// in dev mode, it fails because the schema of our test CorDapp is missing
34+
assertThatExceptionOfType(HibernateSchemaChangeException::class.java)
35+
.isThrownBy {
36+
startNode(NodeParameters(additionalCordapps = listOf(TestCordapp.findCordapp("net.corda.testing.missingmigrationcordapp")))).getOrThrow()
37+
}
38+
.withMessage("Incompatible schema change detected. Please run schema migration scripts (node with sub-command run-migration-scripts). Reason: Schema-validation: missing table [test_table]")
39+
40+
// without devMode, it doesn't even get this far as it complains about the schema migration missing.
41+
assertThatExceptionOfType(CouldNotCreateDataSourceException::class.java)
42+
.isThrownBy {
43+
startNode(
44+
ALICE_NAME,
45+
false,
46+
NodeParameters(additionalCordapps = listOf(TestCordapp.findCordapp("net.corda.testing.missingmigrationcordapp")))).getOrThrow()
47+
}
48+
.withMessage("Could not create the DataSource: No migration defined for schema: net.corda.testing.missingmigrationcordapp.MissingMigrationSchema v1")
49+
}
50+
}
2251
}

node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt

+3-3
Original file line numberDiff line numberDiff line change
@@ -469,9 +469,9 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
469469
pendingCoreChanges = schemaMigration.getPendingChangesCount(schemaService.internalSchemas, true)
470470
}
471471
if(updateAppSchemas) {
472-
schemaMigration.runMigration(!updateAppSchemasWithCheckpoints && haveCheckpoints, schemaService.appSchemas, false)
472+
schemaMigration.runMigration(!updateAppSchemasWithCheckpoints && haveCheckpoints, schemaService.appSchemas, !configuration.devMode)
473473
} else {
474-
pendingAppChanges = schemaMigration.getPendingChangesCount(schemaService.appSchemas, false)
474+
pendingAppChanges = schemaMigration.getPendingChangesCount(schemaService.appSchemas, !configuration.devMode)
475475
}
476476
}
477477
// Now log the vendor string as this will also cause a connection to be tested eagerly.
@@ -1023,7 +1023,7 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
10231023
database.startHikariPool(configuration.dataSourceProperties, metricRegistry) { dataSource, haveCheckpoints ->
10241024
SchemaMigration(dataSource, cordappLoader, configuration.baseDirectory, configuration.myLegalName)
10251025
.checkOrUpdate(schemaService.internalSchemas, runMigrationScripts, haveCheckpoints, true)
1026-
.checkOrUpdate(schemaService.appSchemas, runMigrationScripts, haveCheckpoints && !allowAppSchemaUpgradeWithCheckpoints, false)
1026+
.checkOrUpdate(schemaService.appSchemas, runMigrationScripts, haveCheckpoints && !allowAppSchemaUpgradeWithCheckpoints, !configuration.devMode)
10271027
}
10281028

10291029
/** Loads and starts a notary service if it is configured. */

settings.gradle

+1
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ include 'serialization-djvm:deserializers'
101101
include 'serialization-tests'
102102
include 'testing:cordapps:dbfailure:dbfcontracts'
103103
include 'testing:cordapps:dbfailure:dbfworkflows'
104+
include 'testing:cordapps:missingmigration'
104105

105106
// Common libraries - start
106107
include 'common-validation'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
apply plugin: 'kotlin'
2+
//apply plugin: 'net.corda.plugins.cordapp'
3+
//apply plugin: 'net.corda.plugins.quasar-utils'
4+
5+
dependencies {
6+
compile project(":core")
7+
}
8+
9+
jar {
10+
baseName "testing-missingmigration-cordapp"
11+
manifest {
12+
// This JAR is part of Corda's testing framework.
13+
// Driver will not include it as part of an out-of-process node.
14+
attributes('Corda-Testing': true)
15+
}
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package net.corda.testing.missingmigrationcordapp
2+
3+
import net.corda.core.schemas.MappedSchema
4+
import net.corda.core.schemas.PersistentState
5+
import javax.persistence.Column
6+
import javax.persistence.Entity
7+
import javax.persistence.Table
8+
9+
object MissingMigrationSchema
10+
11+
object MissingMigrationSchemaV1 : MappedSchema(
12+
schemaFamily = MissingMigrationSchema.javaClass,
13+
version = 1,
14+
mappedTypes = listOf(MissingMigrationSchemaV1.TestEntity::class.java)) {
15+
16+
@Entity
17+
@Table(name = "test_table")
18+
class TestEntity(
19+
@Column(name = "random_value")
20+
var randomValue: String
21+
) : PersistentState() {
22+
constructor() : this("")
23+
}
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package net.corda.testing.missingmigrationcordapp
2+
3+
import net.corda.core.flows.FlowLogic
4+
import net.corda.core.flows.InitiatingFlow
5+
import net.corda.core.flows.StartableByRPC
6+
7+
@StartableByRPC
8+
@InitiatingFlow
9+
class SimpleFlow : FlowLogic<Unit>() {
10+
override fun call() {
11+
logger.info("Running simple flow doing nothing")
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package net.corda.testing.missingmigrationcordapp
2+
3+
import net.corda.core.identity.AbstractParty
4+
import net.corda.core.schemas.MappedSchema
5+
import net.corda.core.schemas.PersistentState
6+
import net.corda.core.schemas.QueryableState
7+
8+
class TestEntity(val randomValue: String, override val participants: List<AbstractParty>) : QueryableState {
9+
override fun supportedSchemas(): Iterable<MappedSchema> {
10+
return listOf(MissingMigrationSchemaV1)
11+
}
12+
13+
override fun generateMappedObject(schema: MappedSchema): PersistentState {
14+
return MissingMigrationSchemaV1.TestEntity(randomValue)
15+
}
16+
}

0 commit comments

Comments
 (0)