1

Initial import

This commit is contained in:
2018-02-25 07:43:48 +02:00
commit 330d53df94
19 changed files with 897 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
build
.gradle
.idea
.lazybones
**/*.iml
out

48
README.md Normal file
View File

@@ -0,0 +1,48 @@
Ratpack project template
-----------------------------
You have just created a basic Groovy Ratpack application. It doesn't do much
at this point, but we have set you up with a standard project structure, a
Guice back Registry, simple home page, and Spock for writing tests (because
you'd be mad not to use it).
In this project you get:
* A Gradle build file with pre-built Gradle wrapper
* A tiny home page at src/ratpack/templates/index.html (it's a template)
* A routing file at src/ratpack/Ratpack.groovy
* Reloading enabled in build.gradle
* A standard project structure:
<proj>
|
+- src
|
+- ratpack
| |
| +- Ratpack.groovy
| +- ratpack.properties
| +- public // Static assets in here
| |
| +- images
| +- lib
| +- scripts
| +- styles
|
+- main
| |
| +- groovy
|
+- // App classes in here!
|
+- test
|
+- groovy
|
+- // Spock tests in here!
That's it! You can start the basic app with
./gradlew run
but it's up to you to add the bells, whistles, and meat of the application.

37
build.gradle Normal file
View File

@@ -0,0 +1,37 @@
buildscript {
repositories {
jcenter()
}
dependencies {
classpath "io.ratpack:ratpack-gradle:1.5.1"
classpath 'com.h2database:h2:1.4.191'
}
}
plugins {
id "org.flywaydb.flyway" version "5.0.7"
id "io.ratpack.ratpack-groovy" version "1.5.1"
id 'idea'
}
repositories {
jcenter()
}
dependencies {
compile ratpack.dependency('h2')
compile ratpack.dependency('jdbc-tx')
compile 'org.flywaydb:flyway-core:5.0.7'
runtime 'org.slf4j:slf4j-simple:1.7.25'
testCompile ratpack.dependency('test')
testCompile 'org.spockframework:spock-core:1.0-groovy-2.4'
testCompile 'cglib:cglib:2.2.2'
testCompile 'org.objenesis:objenesis:2.1'
}
flyway {
url = 'jdbc:h2:mem:dbtdb'
user = 'SA'
}
run.dependsOn(flywayMigrate)

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,6 @@
#Fri Feb 23 08:49:01 EET 2018
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.9-bin.zip

160
gradlew vendored Executable file
View File

@@ -0,0 +1,160 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

90
gradlew.bat vendored Normal file
View File

@@ -0,0 +1,90 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@@ -0,0 +1,62 @@
package com.devsoap.dbt
import java.nio.charset.StandardCharsets
import java.security.MessageDigest
class BlockTransaction implements Serializable {
String id = UUID.randomUUID().toString()
List<Query> queries = []
boolean completed = false
boolean executed = false
boolean rolledback = false
/**
* Executes a query in the transaction
*
* @param query
* the query to execute
* @return
* the result of the query
*/
void execute(String query) {
queries << new Query(queries.empty? null : queries.last(), query)
}
/**
* End the current transaction
*
* @return
*/
void end() {
completed = true
}
// A block in the chain
static final class Query implements Serializable {
String data
String hash
long timeStamp
Object result
Query() {
// For serialization
}
Query(Query previous, String data) {
this.data = data
timeStamp = new Date().getTime()
hash = generateHash(previous?.hash)
}
private final String generateHash(String previousHash) {
def digest = MessageDigest.getInstance('SHA-256')
def hash = digest.digest("${previousHash?:''}$timeStamp$data".getBytes(StandardCharsets.UTF_8))
hash.encodeHex().toString()
}
}
}

View File

@@ -0,0 +1,112 @@
package com.devsoap.dbt
import com.devsoap.dbt.config.DBTConfig
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.ObjectMapper
import groovy.util.logging.Log
import ratpack.exec.Promise
import ratpack.http.client.HttpClient
import ratpack.service.Service
import javax.inject.Inject
@Log
class DBTManager implements Service {
private final String ledgerUrl
private final HttpClient httpClient
private final ObjectMapper mapper
@Inject
DBTManager(DBTConfig config, HttpClient httpClient, ObjectMapper mapper){
ledgerUrl = config.ledger.url
this.httpClient = httpClient
this.mapper = mapper
}
Promise<JsonNode> execute(ExecuteQuery queryBuilder) {
log.info("Executing new transaction")
def builder = new TransactionBuilder(this)
queryBuilder.build(builder)
def transaction = builder.build()
log.info("Sending transaction $transaction.id to ledger")
httpClient.post(ledgerUrl.toURI(), { spec ->
spec.body.text(mapper.writeValueAsString(transaction))
}).flatMap { response ->
Promise.value(mapper.readTree(response.body.text))
}
}
Promise<JsonNode> execute(String transactionId, ExecuteQuery queryBuilder) {
log.info("Amending existing transaction $transactionId")
log.info("Getting transaction $transactionId from ledger")
httpClient.get(ledgerUrl.toURI(), { spec ->
spec.headers.add('X-Transaction-Id', transactionId)
}).flatMap { response ->
def oldTransaction = mapper.readValue(response.body.text, BlockTransaction)
if(oldTransaction == null) {
throw new RuntimeException("Transaction with id $transactionId could not be found")
}
if(oldTransaction.completed) {
throw new RuntimeException("Cannot modify a completed transaction")
}
def builder = new TransactionBuilder(this, oldTransaction)
queryBuilder.build(builder)
def transaction = builder.build()
if(transaction.id != transactionId) {
throw new RuntimeException("Transaction id changed")
}
log.info("Sending transaction $transactionId to ledger")
httpClient.post(ledgerUrl.toURI(), { spec ->
spec.body.text(mapper.writeValueAsString(transaction))
})
}.flatMap { response ->
Promise.value(mapper.readTree(response.body.text))
}
}
class TransactionBuilder {
private final List<String> queries = []
private final DBTManager manager
private final BlockTransaction transaction
private TransactionBuilder(DBTManager manager){
this(manager, new BlockTransaction())
}
private TransactionBuilder(DBTManager manager, BlockTransaction transaction) {
this.manager = manager
this.transaction = transaction
}
void query(String sql){
queries << sql
}
String id() {
transaction.id
}
void complete() {
transaction.end()
}
private BlockTransaction build() {
queries.each { transaction.execute(it) }
transaction
}
}
@FunctionalInterface
interface ExecuteQuery {
void build(TransactionBuilder builder)
}
}

View File

@@ -0,0 +1,15 @@
package com.devsoap.dbt.app
import org.flywaydb.core.Flyway
import ratpack.service.Service
import ratpack.service.StartEvent
import javax.sql.DataSource
class DatabaseService implements Service {
@Override
void onStart(StartEvent event){
new Flyway(dataSource: event.registry.get(DataSource)).migrate()
}
}

View File

@@ -0,0 +1,5 @@
package com.devsoap.dbt.config
class DBTConfig {
LedgerConfig ledger = new LedgerConfig()
}

View File

@@ -0,0 +1,5 @@
package com.devsoap.dbt.config
class LedgerConfig {
String url = 'http://localhost:5050/ledger'
}

View File

@@ -0,0 +1,93 @@
package com.devsoap.dbt.handlers
import com.devsoap.dbt.BlockTransaction
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.node.ArrayNode
import groovy.util.logging.Log
import ratpack.exec.Promise
import ratpack.handling.Context
import ratpack.handling.Handler
import ratpack.http.Status
import ratpack.jdbctx.Transaction
import javax.sql.DataSource
import java.sql.ResultSet
@Log
class ExecutorHandler implements Handler {
static final String PATH = 'executor'
@Override
void handle(Context ctx) throws Exception {
ctx.request.body.then { body ->
def mapper = ctx.get(ObjectMapper)
def ds = ctx.get(DataSource)
def transaction = mapper.readValue(body.text, BlockTransaction)
if(!validateChain(transaction)) {
ctx.response.status = Status.of(400, 'Transaction chain invalid')
return
}
executeCommands(ds, mapper, transaction).then {
transaction.executed = true
ctx.response.send(mapper.writeValueAsString(transaction))
}
}
}
boolean validateChain(BlockTransaction transaction) {
//FIXME
true
}
Promise<BlockTransaction> executeCommands(DataSource ds, ObjectMapper mapper, BlockTransaction transaction) {
def txDs = Transaction.dataSource(ds)
def tx = Transaction.create { ds.connection }
tx.wrap {
Promise.sync {
transaction.queries.each { block ->
log.info "Executing $block.data ..."
if(block.data.toLowerCase().startsWith("select")){
def result = txDs.connection
.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE)
.executeQuery(block.data)
block.result = toJson(mapper, result)
} else {
txDs.connection.createStatement().execute(block.data)
}
}
transaction
}
}
}
private static JsonNode toJson(ObjectMapper mapper, ResultSet resultSet) {
def json = mapper.createObjectNode()
if(resultSet.last()) {
int rows = resultSet.row
log.info("Converting $rows rows to json")
resultSet.beforeFirst()
resultSet.metaData.columnCount.times { column ->
def columnIndex = column + 1
def columnName = resultSet.metaData.getColumnName(columnIndex)
ArrayNode columnValue = json.get(columnName)
if(!columnValue) {
columnValue = mapper.createArrayNode()
json.set(columnName, columnValue)
}
resultSet.beforeFirst()
while(resultSet.next()) {
columnValue.addPOJO(resultSet.getObject(columnIndex))
}
}
}
//mapper.writeValueAsString(json)
mapper.valueToTree(json)
}
}

View File

@@ -0,0 +1,51 @@
package com.devsoap.dbt.handlers
import com.devsoap.dbt.BlockTransaction
import com.devsoap.dbt.services.LedgerService
import com.fasterxml.jackson.databind.ObjectMapper
import groovy.util.logging.Log
import ratpack.handling.Context
import ratpack.handling.Handler
@Log
class LedgerHandler implements Handler {
static final String PATH = 'ledger'
@Override
void handle(Context ctx) {
def ledgerService = ctx.get(LedgerService)
ctx.byMethod {
delegate = it
get({
def transaction = ledgerService.fetchTransaction(ctx.request.headers['X-Transaction-Id'].toString())
def mapper = ctx.get(ObjectMapper)
ctx.response.send(mapper.writeValueAsString(transaction))
} as Handler)
post({
ctx.request.body.then { body ->
def mapper = ctx.get(ObjectMapper)
def transaction = mapper.readValue(body.text, BlockTransaction)
def existingTransaction = ledgerService.fetchTransaction(transaction.id)
if(existingTransaction) {
ledgerService.updateTransaction(transaction)
} else {
log.info("Creating new transaction")
ledgerService.newTransaction(transaction)
}
if(transaction.completed){
log.info("Sending transaction $transaction.id to executor")
ctx.redirect(ExecutorHandler.PATH)
} else {
ctx.response.send(mapper.writeValueAsString(transaction))
}
}
} as Handler)
}
}
}

View File

@@ -0,0 +1,33 @@
package com.devsoap.dbt.services
import com.devsoap.dbt.BlockTransaction
import groovy.util.logging.Log
import ratpack.service.Service
import ratpack.service.StartEvent
import ratpack.service.StopEvent
@Log
class LedgerService implements Service {
static final transient List<BlockTransaction> transactions = []
BlockTransaction fetchTransaction(String transactionId) {
log.info("Fetching transaction $transactionId")
log.info("Transactions:$transactions")
transactions.find {it.id == transactionId}
}
String newTransaction(BlockTransaction transaction) {
log.info("Adding new transaction $transaction.id")
transactions << transaction
transaction.id
}
String updateTransaction(BlockTransaction transaction) {
log.info("Updating transaction $transaction.id")
def existingTransaction = fetchTransaction(transaction.id)
def index = transactions.indexOf(existingTransaction)
transactions.remove(index)
transactions.add(index, transaction)
}
}

View File

@@ -0,0 +1,4 @@
create table LOGS (
LOG_ID int not null,
LOG_VALUE varchar(100) not null
);

View File

@@ -0,0 +1,75 @@
import com.devsoap.dbt.app.DatabaseService
import com.devsoap.dbt.config.DBTConfig
import com.devsoap.dbt.DBTManager
import com.devsoap.dbt.handlers.ExecutorHandler
import com.devsoap.dbt.handlers.LedgerHandler
import com.devsoap.dbt.services.LedgerService
import com.fasterxml.jackson.databind.ObjectMapper
import org.h2.jdbcx.JdbcDataSource
import javax.sql.DataSource
import static ratpack.groovy.Groovy.ratpack
ratpack {
serverConfig {
/**
* DBT Framework config
*/
require("", DBTConfig)
}
bindings {
bindInstance(new ObjectMapper())
bindInstance(DataSource, new JdbcDataSource(url: 'jdbc:h2:mem:dbtdb;DB_CLOSE_DELAY=-1', user: ''))
bindInstance(new DatabaseService())
/**
* DBT Framework manager
*/
bind(DBTManager)
bind(LedgerService)
bind(ExecutorHandler)
bind(LedgerHandler)
}
handlers {
/**
* DBT Framework handlers
*/
path('executor', ExecutorHandler)
path('ledger', LedgerHandler)
/**
* Consumer services
*/
get('frontend') {
get(DBTManager).execute { transaction ->
transaction.query("INSERT INTO LOGS(LOG_ID,LOG_VALUE) VALUES (${new Random().nextInt()}, 'HELLO')")
}.then {
redirect("/gateway/${it['id'].textValue()}")
}
}
get('gateway/:transactionId?') {
get(DBTManager).execute(pathTokens.transactionId, { transaction ->
transaction.query("INSERT INTO LOGS(LOG_ID,LOG_VALUE) VALUES (${new Random().nextInt()}, 'WORLD')")
}).then {
redirect("/gateway2/${it['id'].textValue()}")
}
}
get('gateway2/:transactionId?') {
get(DBTManager).execute(pathTokens.transactionId, { transaction ->
transaction.query("SELECT * FROM LOGS")
transaction.complete()
}).then {
render it.toString()
}
}
}
}

View File

@@ -0,0 +1,17 @@
package com.devsoap.dbt.framework
import com.fasterxml.jackson.databind.ObjectMapper
import ratpack.groovy.test.GroovyRatpackMainApplicationUnderTest
import spock.lang.AutoCleanup
import spock.lang.Specification
class ExecutorSpec extends Specification {
def mapper = new ObjectMapper()
@AutoCleanup
def aut = new GroovyRatpackMainApplicationUnderTest()
}

View File

@@ -0,0 +1,78 @@
package com.devsoap.dbt.framework
import com.devsoap.dbt.BlockTransaction
import com.devsoap.dbt.handlers.LedgerHandler
import com.fasterxml.jackson.databind.ObjectMapper
import groovy.json.JsonSlurper
import ratpack.groovy.test.GroovyRatpackMainApplicationUnderTest
import spock.lang.AutoCleanup
import spock.lang.Specification
class LedgerSpec extends Specification {
def mapper = new ObjectMapper()
def jsonSlurper = new JsonSlurper()
@AutoCleanup
def aut = new GroovyRatpackMainApplicationUnderTest()
void 'transaction sent to ledger'() {
setup:
def transaction = new BlockTransaction()
transaction.execute("SELECT * FROM LOGS")
when:
def response = mapper.readValue(aut.httpClient.requestSpec { spec ->
spec.body.text(mapper.writeValueAsString(transaction))
}.post(LedgerHandler.PATH).body.text, BlockTransaction)
then:
response.id == transaction.id
response.completed == false
}
void 'completed transaction marked as completed'() {
setup:
def transaction = new BlockTransaction()
transaction.execute("SELECT * FROM LOGS")
transaction.end()
when:
def response = mapper.readValue(aut.httpClient.requestSpec { spec ->
spec.body.text(mapper.writeValueAsString(transaction))
}.post(LedgerHandler.PATH).body.text, BlockTransaction)
then:
response.id == transaction.id
response.completed == true
}
void 'completed transaction sent to executor from ledger'() {
setup:
def transaction = new BlockTransaction()
transaction.execute("SELECT * FROM LOGS")
transaction.end()
when:
def response = mapper.readValue(aut.httpClient.requestSpec { spec ->
spec.body.text(mapper.writeValueAsString(transaction))
}.post(LedgerHandler.PATH).body.text, BlockTransaction)
then:
response.id == transaction.id
response.executed == true
response.rolledback == false
response.completed == true
}
void 'result is attached to block and executed in order'() {
setup:
def transaction = new BlockTransaction()
transaction.execute("INSERT INTO LOGS(LOG_ID,LOG_VALUE) VALUES (1, 'HELLO')")
transaction.execute("SELECT * FROM LOGS")
transaction.end()
when:
def response = mapper.readValue(aut.httpClient.requestSpec { spec ->
spec.body.text(mapper.writeValueAsString(transaction))
}.post(LedgerHandler.PATH).body.text, BlockTransaction)
def json = jsonSlurper.parseText(response.queries[1].result)
then:
response.id == transaction.id
json.LOG_ID.first() == 1
json.LOG_VALUE.first() == 'HELLO'
}
}