All Downloads are FREE. Search and download functionalities are using the official Maven repository.

migratedb.v1.integrationtest.util.dsl.Fw.kt Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2022-2024 The MigrateDB contributors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package migratedb.v1.integrationtest.util.dsl

import migratedb.v1.integrationtest.database.*
import migratedb.v1.testing.util.base.Args
import org.flywaydb.core.api.MigrationType
import org.flywaydb.core.api.MigrationVersion
import org.flywaydb.core.api.configuration.FluentConfiguration
import org.flywaydb.core.api.logging.LogFactory
import org.flywaydb.core.internal.callback.NoopCallbackExecutor
import org.flywaydb.core.internal.jdbc.JdbcConnectionFactory
import org.flywaydb.core.internal.logging.multi.MultiLogger
import org.flywaydb.core.internal.parser.ParsingContext
import org.flywaydb.core.internal.schemahistory.AppliedMigration
import org.flywaydb.core.internal.schemahistory.SchemaHistoryFactory
import kotlin.random.Random

class DatabasesSupportedByFw : Args(
    functionHasOneParameter = OneParam.YES,
    *databases()
) {
    companion object {
        fun databases() = arrayOf(
            Sqlite.V3_8_11_2,
            Sqlite.V3_36_0_3,
            Derby.V10_15_2_0,
            MariaDb.V10_6,
            SqlServer.V2019_CU15,
            Hsqldb.V2_6_1,
            Postgres.V14,
            H2.V2_1_210,
            Informix.V14_10,
        )

        init {
            // Silence!
            LogFactory.setLogCreator { MultiLogger(emptyList()) }
        }
    }
}

//
interface FwSchemaHistorySpec {
    fun entry(version: String?, description: String, type: String, success: Boolean)
}

fun Dsl.GivenStep.fwSchemaHistory(
    table: String,
    block: (FwSchemaHistorySpec).() -> Unit
): List {
    val result = mutableListOf()
    extend { databaseContext ->
        val config = FluentConfiguration()
            .dataSource(databaseContext.adminDataSource)
            .table(table)
            .apply { databaseContext.schemaName?.let { schemas("$it") } }
        FwSchemaHistory(config, Random(seed = 0)).use { schemaHistory ->
            schemaHistory.create()
            object : FwSchemaHistorySpec {
                override fun entry(version: String?, description: String, type: String, success: Boolean) {
                    schemaHistory.add(version, description, type, "script", 0, 0, success)
                }
            }.block()
            result.addAll(schemaHistory.get())
        }
    }
    return result
}

fun Dsl.GivenStep.fwSchemaHistory(table: String, size: Int): List {
    val result = mutableListOf()
    extend { databaseContext ->
        val config = FluentConfiguration()
            .dataSource(databaseContext.adminDataSource)
            .table(table)
            .apply { databaseContext.schemaName?.let { schemas("$it") } }
        FwSchemaHistory(config, Random(seed = size)).use { schemaHistory ->
            schemaHistory.create()
            val remaining = size - schemaHistory.get().size
            repeat(remaining.coerceAtLeast(0)) {
                schemaHistory.addRandom()
            }
            result.addAll(schemaHistory.get())
        }
    }
    return result
}


class FwSchemaHistory(private val configuration: FluentConfiguration, private val random: Random) : AutoCloseable {
    private val jdbcConnectionFactory = JdbcConnectionFactory(configuration.dataSource, configuration, null)
    private val database = jdbcConnectionFactory.databaseType.createDatabase(
        configuration,
        false,
        jdbcConnectionFactory,
        null
    )
    private val parsingContext = ParsingContext()
    private val sqlScriptFactory =
        jdbcConnectionFactory.databaseType.createSqlScriptFactory(configuration, parsingContext)
    private val noCallbackSqlScriptExecutorFactory =
        jdbcConnectionFactory.databaseType.createSqlScriptExecutorFactory(
            jdbcConnectionFactory,
            NoopCallbackExecutor.INSTANCE,
            null
        )
    private val schemas = SchemaHistoryFactory.prepareSchemas(configuration, database)
    private val defaultSchema = schemas.left
    private val delegate =
        SchemaHistoryFactory.getSchemaHistory(
            configuration,
            noCallbackSqlScriptExecutorFactory,
            sqlScriptFactory,
            database,
            defaultSchema,
            null
        )
    private val versionedTypes = listOf(
        "BASELINE",
        "CUSTOM",
        "UNDO_CUSTOM",
        "UNDO_JDBC",
        "UNDO_SQL",
        "UNDO_SPRING_JDBC",
        "UNDO_SCRIPT",
        "DELETE",
        "JDBC",
        "JDBC_STATE_SCRIPT",
        "SQL",
        "SQL_STATE_SCRIPT",
        "SCRIPT",
        "SPRING_JDBC",
        "SCRIPT_BASELINE",
        "JDBC_BASELINE",
        "SQL_BASELINE"
    )
    private val repeatableTypes = listOf(
        "SQL",
        "SCRIPT",
        "JDBC",
        "SPRING_JDBC",
        "DELETE",
        "CUSTOM",
    )

    fun addRandom() {
        val version: String?
        val type: String
        when (random.nextBoolean()) {
            true -> {     // versioned
                version = random.nextInt(1, Int.MAX_VALUE).toString()
                type = versionedTypes.random(random)
            }

            false -> {    // repeatable
                version = null
                type = repeatableTypes.random(random)
            }
        }
        val description = randomDescription()
        val script = "script" + random.nextInt()
        val checksum = when (random.nextBoolean()) {
            true -> random.nextInt()
            false -> null
        }
        add(version, description, type, script, checksum, random.nextInt(), random.nextBoolean())
    }

    private fun randomDescription(): String {
        return when (random.nextInt(4)) {
            0 -> ""
            1 -> "D"
            2 -> "__"
            else -> "123"
        }
    }

    fun add(
        version: String?,
        description: String,
        type: String,
        script: String,
        checksum: Int?,
        executionTime: Int,
        success: Boolean
    ) {
        delegate.addAppliedMigration(
            version?.let { MigrationVersion.fromVersion(it) },
            description,
            MigrationType.CUSTOM,
            script,
            checksum,
            executionTime,
            success
        )
        val table = defaultSchema.getTable(configuration.table)
        val justInserted = get().last().installedRank
        database.mainConnection.jdbcTemplate.update(
            "update $table set ${database.quote("type")} = ?" +
                " where ${database.quote("installed_rank")}  = ?",
            type, justInserted
        )
    }

    fun create() {
        delegate.create(false)
    }

    fun get(): List = delegate.allAppliedMigrations()


    override fun close() {
        database.use { }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy