catchError {

    def combine = { lst -> lst.inject([]) { acc, x -> acc + x } }

    def tidb_config = """
    # Schema lease duration (default: 45s)
    lease = "5s"

    # One table per region (default: true)
    split-table = true

    [log]
    slow-query-file = "slow.log"
    slow-threshold = 0

    [tikv-client]
    # Max time for commit command, must be twice bigger than raft election timeout.
    # Default: 41s.
    commit-timeout = "10ms"

    # Allow TiDB try to use 1PC protocol to commit transactions that involves only one region.
    enable-one-pc = false

    # The max time a Txn may use (in seconds) from its startTS to commitTS. We use
    # it to guarantee GC worker will not influence any active txn. Please make sure
    # that this value is less than gc_life_time - 10s. Default: 590
    max-txn-time-use = 590

    [tikv-client.async-commit]
    # Whether to enable the async commit feature. This feature reduces the latency of the two-phase commit.
    enable = true
    """.stripIndent()

    def pd_config = 'tso-update-physical-interval = "10s"'

    def tikv_config = """
    [storage]
    enable-async-apply-prewrite = true
    """.stripIndent()

    def params = [
        string(name: "TITLE", value: "async-commit"),
        string(name: "IMAGE", value: "hub.pingcap.net/qa/jepsen-control:stable"),
        string(name: "TARBALL_URL", value: "http://fileserver.pingcap.net/download/pingcap/qa/archives/jepsen/tidb-master.tar.gz"),
        string(name: "TIDB_CONFIG", value: tidb_config),
        string(name: "TIKV_CONFIG", value: tikv_config),
        string(name: "PD_CONFIG", value: pd_config),
        string(name: "INIT_TXN_SQL", value: "set @@tidb_enable_async_commit = 0, @@tidb_enable_1pc = 0; set @@tidb_enable_async_commit = 1, @@tidb_enable_1pc = 0; set @@tidb_enable_async_commit = 1, @@tidb_enable_1pc = 1, @@tidb_guarantee_linearizability = 0; set @@tidb_enable_async_commit = 1, @@tidb_enable_1pc = 1, @@tidb_guarantee_linearizability = 1;"),
        booleanParam(name: "REPORT", value: true),
    ]

    def plist = []

    def run = { ->
        def nemesis = [
            [string(name: "NEMESIS", value: "none")],
            [string(name: "NEMESIS", value: "shuffle-leader,shuffle-region,partition")],
            [string(name: "NEMESIS", value: "shuffle-leader,shuffle-region,random-merge,kill")],
        ]
        [[params], nemesis, plist].combinations().collect(combine).each {
            try {
                build(job: "jepsen-test", parameters: it)
            } catch (e) {
                echo("Error: $e")
            }
        }
    }

    // sequential, to test external consistency
    plist = []
    plist.addAll([[
        [string(name: "WORKLOAD", value: "sequential")],
    ], [
        [string(name: "TXN_MODE", value: "optimistic"), string(name: "READ_LOCK", value: "")],
        [string(name: "TXN_MODE", value: "optimistic")],
        [string(name: "TXN_MODE", value: "pessimistic")],
        [string(name: "TXN_MODE", value: "mixed")],
    ]].combinations().collect(combine))
    run()

    // bank
    plist = []
    plist.addAll([[
        [string(name: "WORKLOAD", value: "bank")],
        [string(name: "WORKLOAD", value: "bank-multitable")],
    ], [
        [string(name: "TXN_MODE", value: "optimistic"), string(name: "READ_LOCK", value: "")],
        [string(name: "TXN_MODE", value: "optimistic")],
        [string(name: "TXN_MODE", value: "pessimistic")],
        [string(name: "TXN_MODE", value: "mixed")],
    ], [
        [booleanParam(name: "UPDATE_IN_PLACE", value: true)],
        [booleanParam(name: "UPDATE_IN_PLACE", value: false)],
    ]].combinations().collect(combine))
    run()

    // long-fork
    plist = []
    plist.addAll([[
        [string(name: "WORKLOAD", value: "long-fork")],
    ], [
        [string(name: "TXN_MODE", value: "optimistic")],
        [string(name: "TXN_MODE", value: "pessimistic")],
        [string(name: "TXN_MODE", value: "mixed")],
    ], [
        [string(name: "READ_LOCK", value: "")],
    ], [
        [booleanParam(name: "USE_INDEX", value: true)],
        [booleanParam(name: "USE_INDEX", value: false)],
    ]].combinations().collect(combine))
    run()

    // monotonic
    plist = []
    plist.addAll([[
        [string(name: "WORKLOAD", value: "monotonic")],
    ], [
        [string(name: "TXN_MODE", value: "optimistic")],
        [string(name: "TXN_MODE", value: "pessimistic")],
        [string(name: "TXN_MODE", value: "mixed")],
    ], [
        [booleanParam(name: "USE_INDEX", value: true)],
        [booleanParam(name: "USE_INDEX", value: false)],
    ], [
        [booleanParam(name: "UPDATE_IN_PLACE", value: true)],
        [booleanParam(name: "UPDATE_IN_PLACE", value: false)],
    ]].combinations().collect(combine))
    run()

    // txn-cycle
    plist = []
    plist.addAll([[
        [string(name: "WORKLOAD", value: "txn-cycle")],
    ], [
        [string(name: "TXN_MODE", value: "optimistic"), string(name: "READ_LOCK", value: "")],
        [string(name: "TXN_MODE", value: "optimistic")],
        [string(name: "TXN_MODE", value: "pessimistic")],
        [string(name: "TXN_MODE", value: "mixed")],
    ], [
        [booleanParam(name: "USE_INDEX", value: true)],
        [booleanParam(name: "USE_INDEX", value: false)],
    ]].combinations().collect(combine))
    run()

    // set
    plist = []
    plist.addAll([[
        [string(name: "WORKLOAD", value: "set")],
    ], [
        [string(name: "TXN_MODE", value: "optimistic")],
        [string(name: "TXN_MODE", value: "pessimistic")],
        [string(name: "TXN_MODE", value: "mixed")],
    ], [
        [string(name: "READ_LOCK", value: "")],
        [string(name: "READ_LOCK", value: "update")],
    ]].combinations().collect(combine))
    run()

    // others
    plist = []
    plist.addAll([[
        [string(name: "WORKLOAD", value: "append")],
        [string(name: "WORKLOAD", value: "set-cas")],
        [string(name: "WORKLOAD", value: "register")],
        [string(name: "WORKLOAD", value: "comments")],
    ], [
        [string(name: "TXN_MODE", value: "optimistic"), string(name: "READ_LOCK", value: "")],
        [string(name: "TXN_MODE", value: "optimistic")],
        [string(name: "TXN_MODE", value: "pessimistic")],
        [string(name: "TXN_MODE", value: "mixed")],
    ]].combinations().collect(combine))
    run()

}
